background

Spring manages mybatis by relying on Mybatis – Spring. What does this do?

Spring transaction manager

TransactionAspectSupport#invokeWithinTransaction() invokes the spring transaction template

@Nullable
protected Object invokeWithinTransaction(Method method, @NullableClass<? > targetClass,final InvocationCallback invocation) throws Throwable {
   // If the transaction attribute is null, the method is non-transactional.
   TransactionAttributeSource tas = getTransactionAttributeSource();
   finalTransactionAttribute txAttr = (tas ! =null ? tas.getTransactionAttribute(method, targetClass) : null);
   final TransactionManager tm = determineTransactionManager(txAttr);
   / /... Omit the other
   PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
   final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

   if (txAttr == null| |! (ptminstanceof CallbackPreferringPlatformTransactionManager)) {
      // Standard transaction demarcation with getTransaction and commit/rollback calls.
      // Create transaction
      TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

      Object retVal;
      try {
         // This is an around advice: Invoke the next interceptor in the chain.
         // This will normally result in a target object being invoked.
         // Invoke the proxy method
         retVal = invocation.proceedWithInvocation();
      }
      catch (Throwable ex) {
         // target invocation exception
         // An exception occurs, the transaction is rolled back and the exception continues to be thrown up
         completeTransactionAfterThrowing(txInfo, ex);
         throw ex;
      }
      finally {
         cleanupTransactionInfo(txInfo);
      }

      if(retVal ! =null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
         // Set rollback-only in case of Vavr failure matching our rollback rules...
         TransactionStatus status = txInfo.getTransactionStatus();
         if(status ! =null&& txAttr ! =null) { retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status); }}// Commit the transaction
      commitTransactionAfterReturning(txInfo);
      returnretVal; }}Copy the code

DataSourceTransactionManager, for example, a typical transaction through the following stages of life cycle

  1. Creating New Transaction
  2. Acquired Connection
  3. Switching JDBC Connection to manual commit
  4. Initiating a transaction commit
  5. Commit a TRANSACTION (RESEARCH case of JDBC Transaction)
  6. Releasing JDBC Connection

Mybatis general usage

  SqlSession sqlSession = sqlSessionFactory.openSession();
  sqlSession.selectOne("xxx");
  sqlSession.commit();
  sqlSession.close();
Copy the code

Around SqlSession, there are several steps such as get, use, commit and close

Spring management mybatis

If Spring wants to manage MyBatis, it must solve two problems, broker SqlSession and manage the LIFECYCLE of SqlSession in a transaction

SqlSessionTemplate

The SqlSessionTemplate proxy SqlSession. Under Spring, all mappers must pass through this section to get a true SqlSession

private class SqlSessionInterceptor implements InvocationHandler {
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    // Get SqlSession, reuse transaction if already obtained
    SqlSession sqlSession = getSqlSession(SqlSessionTemplate.this.sqlSessionFactory,
        SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);
    try {
      Object result = method.invoke(sqlSession, args);
      if(! isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
        // force commit even on non-dirty sessions because some databases require
        // a commit/rollback before calling close()
        sqlSession.commit(true);
      }
      return result;
    } catch (Throwable t) {
      / / to omit
      throw unwrapped;
    } finally {
      if(sqlSession ! =null) {
        closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory); }}}}Copy the code

Manage the SqlSession life cycle

The SqlSession lifecycle must be managed in a transaction, including the commit and close of the SqlSession Spring transaction in TransactionSynchronization provides callback interface, for the third party, including beforeCommit, beforeCompletion, afterCommit, methods of afterCompletion, at the same time Abst Call the above several callback interface ractPlatformTransactionManager when appropriate

In TransactionSynchronizationManager management synchronization needed resources

// Synchronize the required transaction resources, such as Connection, SqlSession
private static final ThreadLocal<Map<Object, Object>> resources =
      new NamedThreadLocal<>("Transactional resources");
/ / synchronization required callback interface, such as mybatis SqlSessionSynchronization
private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
      new NamedThreadLocal<>("Transaction synchronizations");
Copy the code

Spring in getSqlSession SqlSessionSynchronization will be registered as a callback interface, so that the spring transaction can manage the SqlSession lifecycle.

conclusion

Finally, a complete transaction flow:

  1. Creating New Transaction
  2. Acquired Connection
  3. Switching JDBC Connection to manual commit
  • Creating a new SqlSession
  • Registering transaction synchronization for SqlSession
  • Execute various SQL
  • Releasing transactional SqlSession
  • Transaction synchronization committing SqlSession
  • Transaction synchronization deregistering SqlSession
  • Transaction synchronization closing SqlSession
  1. Initiating a transaction commit
  2. Commit a TRANSACTION (RESEARCH case of JDBC Transaction)
  3. Releasing JDBC Connection