目录
目录
1. spring事务管理器开启事务做了些什么事情:
1.1 创建mysql数据库连接:
1.2 开启mysql事务
1.3 将当前事务所使用的连接绑定到ThreadLocal中,供后续执行sql命令使用。
2. mybatis如何集成spring事务管理器?
3.spring事务commit方法如何与DataSource集成
4. mysql相关命令
5. 一个方便调试的数据库Datasource
6. 参考文档:
首先是如何开启事务:
a代码方式:直接调用org.springframework.jdbc.datasource.DataSourceTransactionManager的
b注解方式:@Transaction
这两种方式最终都是调用如下接口的三个方法来实现创建事务,执行commit,执行rollback动作的。
org.springframework.transaction.PlatformTransactionManager#getTransaction
要理解spring事务的原理,重点就是要了解创建事务(getTransaction方法),究竟做了些什么事情。其中@Transaction方式事务,是在AOP代理的拦截方法中执行的创建事务(@Transaction注解method之前创建事务)。
getTransaction方法主要做了以下三件事情:
因此在进入@Transaction注解method之前就已经创建了数据库连接。
@Transaction进入/出method就创建/关闭数据库连接。
因此@Transaction注解,不能包含太大的方法。包含太大的逻辑,就会导致数据库连接占用时间过长。
执行命令:SET autocommit=0
最终存储ThreadLocal为:org.springframework.transaction.support.TransactionSynchronizationManager#resources
// org.springframework.transaction.support.TransactionSynchronizationManager
public abstract class TransactionSynchronizationManager {
// 事务管理器创建的连接,存储位置
private static final ThreadLocal
# 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());
}
}
// 省略部分代码。。。
}
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;
}
org.springframework.transaction.support.TransactionTemplate#execute
调用org.springframework.transaction.PlatformTransactionManager#commit方法的时候,
最终会调用DataSourceUtils.releaseConnection(con, this.dataSource);
最终会将DataSource中的当前数据库连接回收利用(recycle),并且放入DataSource中。
查看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";
org.springframework.jdbc.datasource.DriverManagerDataSource
每次获取连接都是通过驱动真实的和mysql服务器创建连接。每次释放连接都是真实的通过驱动和mysql服务解除连接。
详解 Spring 注解@Transactional事务控制原理
springboot开启声明式事务 - 腾讯云开发者社区-腾讯云
mysql中set autocommit=0与start transaction区别_yygr的博客-CSDN博客