spring事务管理器原理?mybatis如何集成spring事务管理器?spring事务commit方法如何与DataSource集成?

目录

目录

1. spring事务管理器开启事务做了些什么事情:

1.1 创建mysql数据库连接:

1.2 开启mysql事务

1.3 将当前事务所使用的连接绑定到ThreadLocal中,供后续执行sql命令使用。

2. mybatis如何集成spring事务管理器?

3.spring事务commit方法如何与DataSource集成

4. mysql相关命令

5. 一个方便调试的数据库Datasource

6. 参考文档:


1. spring事务管理器开启事务做了些什么事情:

首先是如何开启事务:
a代码方式:直接调用org.springframework.jdbc.datasource.DataSourceTransactionManager的
b注解方式:@Transaction
这两种方式最终都是调用如下接口的三个方法来实现创建事务,执行commit,执行rollback动作的。

org.springframework.transaction.PlatformTransactionManager#getTransaction

要理解spring事务的原理,重点就是要了解创建事务(getTransaction方法),究竟做了些什么事情。其中@Transaction方式事务,是在AOP代理的拦截方法中执行的创建事务(@Transaction注解method之前创建事务)。

getTransaction方法主要做了以下三件事情:


1.1 创建mysql数据库连接:

因此在进入@Transaction注解method之前就已经创建了数据库连接。

@Transaction进入/出method就创建/关闭数据库连接。

因此@Transaction注解,不能包含太大的方法。包含太大的逻辑,就会导致数据库连接占用时间过长。

1.2 开启mysql事务


执行命令:SET autocommit=0

1.3 将当前事务所使用的连接绑定到ThreadLocal中,供后续执行sql命令使用。

最终存储ThreadLocal为:org.springframework.transaction.support.TransactionSynchronizationManager#resources

// org.springframework.transaction.support.TransactionSynchronizationManager

public abstract class TransactionSynchronizationManager {
   // 事务管理器创建的连接,存储位置
   private static final ThreadLocal<Map<Object, Object>> resources =
         new NamedThreadLocal<>("Transactional resources");

# org.springframework.jdbc.datasource.DataSourceTransactionManager
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
   DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
   Connection con = null;

   try {
      if (!txObject.hasConnectionHolder() ||
            txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
         //1.1 创建mysql数据库连接:
         Connection newCon = obtainDataSource().getConnection();  
         if (logger.isDebugEnabled()) {
            logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
         }
         txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
      }
      
      // 省略部分代码。。。
     	if (con.getAutoCommit()) {
				txObject.setMustRestoreAutoCommit(true);
				if (logger.isDebugEnabled()) {
					logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
				}
                1.2 开启mysql事务,执行命令:SET autocommit=0
				con.setAutoCommit(false);
			}
			// 省略部分代码。。。
      // Bind the connection holder to the thread.
      if (txObject.isNewConnectionHolder()) {
         1.3 将当前事务所使用的连接绑定到ThreadLocal中,供后续执行sql命令使用。
         TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
      }
   }
   // 省略部分代码。。。
}

2. mybatis如何集成spring事务管理器?

mybatis执行sql会调用 SqlSessionTemplate获取连接,然后会调用
org.mybatis.spring.SqlSessionUtils#getSqlSession(org.apache.ibatis.session.SqlSessionFactory, org.apache.ibatis.session.ExecutorType, org.springframework.dao.support.PersistenceExceptionTranslator)
方法,这个方法首先会检查事务管理的ThreadLocal中是否已经有了数据库连接,有的话,就直接用此数据库连接(这样就实现了和spring事务管理器的集成,共用数据库连接);如果没有,那么就重新创建一个连接。

因此mybatis不需要做什么配置就可以和spring事务管理器进行自动集成(ThreadLocal是二者集成的纽带),只需要二者使用相同DataSource即可。

# org.mybatis.spring.SqlSessionUtils
public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType,
    PersistenceExceptionTranslator exceptionTranslator) {

  notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);
  notNull(executorType, NO_EXECUTOR_TYPE_SPECIFIED);
  
  // 从事务管理器ThreadLocal中获取连接
  SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);

  SqlSession session = sessionHolder(executorType, holder);
  if (session != null) {
    return session;
  }

  // 没有获取到连接,就重新创建连接
  LOGGER.debug(() -> "Creating a new SqlSession");
  session = sessionFactory.openSession(executorType);

  registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);

  return session;
}

3.spring事务commit方法如何与DataSource集成

 org.springframework.transaction.support.TransactionTemplate#execute

调用org.springframework.transaction.PlatformTransactionManager#commit方法的时候,

最终会调用DataSourceUtils.releaseConnection(con, this.dataSource);

最终会将DataSource中的当前数据库连接回收利用(recycle),并且放入DataSource中。

4. mysql相关命令

查看mysql服务器存在的客户端连接:SELECT * FROM information_schema.PROCESSLIST;

查看mysql所执行的命令(包括查询命令):

show variables where Variable_name="general_log";

set global general_log=on;

show variables where Variable_name="general_log_file";

5. 一个方便调试的数据库Datasource

org.springframework.jdbc.datasource.DriverManagerDataSource

每次获取连接都是通过驱动真实的和mysql服务器创建连接。每次释放连接都是真实的通过驱动和mysql服务解除连接。
 

6. 参考文档:

详解 Spring 注解@Transactional事务控制原理

springboot开启声明式事务 - 腾讯云开发者社区-腾讯云

mysql中set autocommit=0与start transaction区别_yygr的博客-CSDN博客

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值