Mybatis+Spring 时事务时交给谁处理的呢?

Mybatis+Spring 时事务时交给谁处理的呢?

如果业务方法加上 @Transactional 时,是交给 Spring 处理。默认情况下,还是mybatis自己处理事务。

源码证明

在我们调用从 mybatis 代理出来的 mapper 接口时,其实调用 mybatis 的 MapperFactoryBean 对象,该对象是JVM代理对象,其InvocationHandler实现在SqlSessionTemplate中。

public class SqlSessionTemplate implements SqlSession, DisposableBean {
    
    
	//...

     /**
   * Proxy needed to route MyBatis method calls to the proper SqlSession got from Spring's Transaction Manager It also
   * unwraps exceptions thrown by {@code Method#invoke(Object, Object...)} to pass a {@code PersistenceException} to the
   * {@code PersistenceExceptionTranslator}.
   */
  private class SqlSessionInterceptor implements InvocationHandler {
    
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
      SqlSession sqlSession = getSqlSession(SqlSessionTemplate.this.sqlSessionFactory,
          SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);
      try {
    
    
        Object result = method.invoke(sqlSession, args);
        // ******* 1
        if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
    
    
          // force commit even on non-dirty sessions because some databases require
          // a commit/rollback before calling close()
          //即使在非dirty会话上,也会强制提交,因为一些数据库在调用close()之前需要提交/回滚
          sqlSession.commit(true);
        }
        return result;
      } catch (Throwable t) {
    
    
        Throwable unwrapped = unwrapThrowable(t);
        if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
    
    
          // release the connection to avoid a deadlock if the translator is no loaded. See issue #22
          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
          sqlSession = null;
          Throwable translated = SqlSessionTemplate.this.exceptionTranslator
              .translateExceptionIfPossible((PersistenceException) unwrapped);
          if (translated != null) {
    
    
            unwrapped = translated;
          }
        }
        throw unwrapped;
      } finally {
    
    
        if (sqlSession != null) {
    
    
          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
        }
      }
    }
  }
}

关键在于!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)这句代码,调用的是 SqlSessionUtils # isSqlSessionTransactional(SqlSession session, SqlSessionFactory sessionFactory) 方法:

 /**
   * Returns if the {@code SqlSession} passed as an argument is being managed by Spring
   * 如果作为参数传递的SqlSession正在被Spring管理,则返回 true;否则返回false
   * @param session
   *          a MyBatis SqlSession to check -- 要检查的 Mybatis SqlSession
   * @param sessionFactory
   *          the SqlSessionFactory which the SqlSession was built with
   *          -- 构建 SqlSession 时使用的 SqlSessionFactory
   * @return true if session is transactional, otherwise false
   * 	-- 如果session是事务性的,则为true,否则为false
   */
  public static boolean isSqlSessionTransactional(SqlSession session, SqlSessionFactory sessionFactory) {
    
    
    notNull(session, NO_SQL_SESSION_SPECIFIED);
    notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);

    SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);

    return (holder != null) && (holder.getSqlSession() == session);
  }

该方法会检查当前 SqlSession 是否被 Spring 管理,在执行被@Transactional修复方法时,SqlSession就会交给 Spring 管理事务。
当前SqlSession被 Spring 管理时,mybatis 会做出让步,不在主动提交事务。

猜你喜欢

转载自blog.csdn.net/qq_30321211/article/details/112260785