探讨整合Spring前提下Jpa的EntityManager和Mybatis的SqlSession在不加@Transactional时会不会占用连接不释放(核心方法TransactionSynchronizationManager#isSynchronizationActive()用于判断是否开启事务);
EntityManager会主动释放连接,
SqlSession不会主动释放连接,
但是Mapper动态代理类(引用了mybatis-spring.jar整合后产生的Mapper代理类中的SqlSession是代理类SqlSessionTemplate)会主动释放连接即SqlSessionTemplate会主动释放连接
SqlSession (此时连接池数量为2)
demo方法加了 @Transactional下面三个线程可以全部执行打印三个1;不加@Transactional只能执行两个,说明SqlSession不会主动释放连接。
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private SqlSessionFactory sessionFactory;
@Transactional
public void demo(){
User user1=new User();
user1.setId("1");
user1.setName("aaa");
int update = sessionFactory.openSession().update("com.lago.mapper.UserMapper.updateUser", user1);
System.out.println(update);
}
/**
* 探讨整合Spring前提下Jpa的EntityManager和Mybatis的SqlSession在不加@Transactional时会不会占用连接不释放
* @param args
*/
public static void main(String[] args) {
ClassPathXmlApplicationContext classPathXmlApplicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = classPathXmlApplicationContext.getBean(UserService.class);
User user1=new User();
user1.setId("1");
user1.setName("aaa");
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
userService.demo();
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
userService.demo();
}
});
Thread thread3 = new Thread(new Runnable() {
@Override
public void run() {
userService.demo();
}
});
thread.start();
thread2.start();
thread3.start();
}
}
Mapper的动态代理类或SqlSessionTemplate(此时连接池数量为2)
mapper动态代理类里的SqlSession其实是SqlSessionTemplate实例,SqlSessionTemplate是个代理类执行增删改成时会进入invoke方法
代理类在最后也有fianlly方法执行资源的释放(在没有@Transactional事务的情况下)。
SqlsessionTemplate.class
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SqlSession sqlSession = SqlSessionUtils.getSqlSession(SqlSessionTemplate.this.sqlSessionFactory, SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);
Object unwrapped;
try {
Object result = method.invoke(sqlSession, args);
if (!SqlSessionUtils.isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
sqlSession.commit(true);
}
unwrapped = result;
} catch (Throwable var11) {
unwrapped = ExceptionUtil.unwrapThrowable(var11);
if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
sqlSession = null;
Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException)unwrapped);
if (translated != null) {
unwrapped = translated;
}
}
throw (Throwable)unwrapped;
} finally {
if (sqlSession != null) {
SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
}
}
return unwrapped;
}
EntityManager (此时连接池数量为2)
EntityManager是个代理类执行find方法时进入代理类的invoke方法,最后有个finally方法判断是新的EntityManager是自动释放资源(此处)。 EntityManagerFactoryUtils.doGetTransactionalEntityManager(this.targetFactory, this.properties, this.synchronizedWithTransaction);在有无声明式事务时有所不同,后面再研究。
SharedEntityManagerCreator.class
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("equals")) {
return proxy == args[0];
} else if (method.getName().equals("hashCode")) {
return this.hashCode();
} else if (method.getName().equals("toString")) {
return "Shared EntityManager proxy for target factory [" + this.targetFactory + "]";
} else if (method.getName().equals("getEntityManagerFactory")) {
return this.targetFactory;
} else if (!method.getName().equals("getCriteriaBuilder") && !method.getName().equals("getMetamodel")) {
if (method.getName().equals("unwrap")) {
Class<?> targetClass = (Class)args[0];
if (targetClass != null && targetClass.isInstance(proxy)) {
return proxy;
}
} else {
if (method.getName().equals("isOpen")) {
return true;
}
if (method.getName().equals("close")) {
return null;
}
if (method.getName().equals("getTransaction")) {
throw new IllegalStateException("Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead");
}
}
// 此处有无事务不一样 关注下TransactionSynchronizationManager#isSynchronizationActive()
EntityManager target = EntityManagerFactoryUtils.doGetTransactionalEntityManager(this.targetFactory, this.properties, this.synchronizedWithTransaction);
if (method.getName().equals("getTargetEntityManager")) {
if (target == null) {
throw new IllegalStateException("No transactional EntityManager available");
} else {
return target;
}
} else {
if (method.getName().equals("unwrap")) {
Class<?> targetClass = (Class)args[0];
if (targetClass == null) {
return target != null ? target : proxy;
}
if (target == null) {
throw new IllegalStateException("No transactional EntityManager available");
}
} else if (SharedEntityManagerCreator.transactionRequiringMethods.contains(method.getName()) && (target == null || !TransactionSynchronizationManager.isActualTransactionActive() && !target.getTransaction().isActive())) {
throw new TransactionRequiredException("No EntityManager with actual transaction available for current thread - cannot reliably process '" + method.getName() + "' call");
}
boolean isNewEm = false;
if (target == null) {
this.logger.debug("Creating new EntityManager for shared EntityManager invocation");
target = !CollectionUtils.isEmpty(this.properties) ? this.targetFactory.createEntityManager(this.properties) : this.targetFactory.createEntityManager();
isNewEm = true;
}
Object var18;
try {
Object result = method.invoke(target, args);
if (result instanceof Query) {
Query query = (Query)result;
if (isNewEm) {
Class<?>[] ifcs = ClassUtils.getAllInterfacesForClass(query.getClass(), this.proxyClassLoader);
result = Proxy.newProxyInstance(this.proxyClassLoader, ifcs, new SharedEntityManagerCreator.DeferredQueryInvocationHandler(query, target));
isNewEm = false;
} else {
EntityManagerFactoryUtils.applyTransactionTimeout(query, this.targetFactory);
}
}
var18 = result;
} catch (InvocationTargetException var14) {
throw var14.getTargetException();
} finally {
if (isNewEm) {
EntityManagerFactoryUtils.closeEntityManager(target);
}
}
return var18;
}
} else {
try {
return EntityManagerFactory.class.getMethod(method.getName()).invoke(this.targetFactory);
} catch (InvocationTargetException var13) {
throw var13.getTargetException();
}
}
}