@Transactional 到底做了什么?事务是怎么和一个连接绑在一起的?MySQL 那边能看到什么?事务状态放在哪里?这篇用 Spring Framework 7.0.9、HikariCP 和自己起的 MySQL 26.7.0 把一次事务的全过程逐步量出来。
--- 事务管理器被调用的过程(正常提交) 1. doGetTransaction() 2. doBegin(Svc.place,传播 0,只读 false):从连接池拿连接、setAutoCommit(false)、把连接绑定到当前线程 3. 进入 place():事务活跃=true,事务名=Svc.place,绑定的资源=[HikariDataSource] 4. 两条 insert 之间 connection_id():12 和 12(同一个连接) 5. doCommit():connection.commit() 6. doCleanupAfterCompletion():解除绑定、恢复 autoCommit、把连接还给连接池 --- 事务管理器被调用的过程(业务异常回滚) 1. doGetTransaction() 2. doBegin(Svc.place,传播 0,只读 false):从连接池拿连接、setAutoCommit(false)、把连接绑定到当前线程 3. 进入 place():事务活跃=true,事务名=Svc.place,绑定的资源=[HikariDataSource] 4. 两条 insert 之间 connection_id():12 和 12(同一个连接) 5. doRollback():connection.rollback() 6. doCleanupAfterCompletion():解除绑定、恢复 autoCommit、把连接还给连接池 7. 调用者收到 IllegalStateException 两次调用之后表 t 里有 2 行(place(false) 提交了 2 行,place(true) 的 2 行回滚了)
doGetTransaction、doBegin、doCommit 或 doRollback、doCleanupAfterCompletion。
一次 @Transactional place(false) 在 MySQL general_log 里留下的语句(只取执行这个事务的那一个连接 thread_id;连接池后台新建的其它连接的握手语句略去):
13 Query SET autocommit=0
13 Query insert into t(v) values ('a')
13 Query select connection_id()
13 Query insert into t(v) values ('b')
13 Query select connection_id()
13 Query COMMIT
13 Query SET autocommit=1
没有 @Transactional 的 noTx()(两条 insert)留下的语句:
13 Query insert into t(v) values ('x')
13 Query insert into t(v) values ('y')SET autocommit=0、业务语句、COMMIT、SET autocommit=1;没有 @Transactional 时每条语句自己提交。
事务外:isSynchronizationActive=false;isActualTransactionActive=false;资源 [] --- noTx() 1. 进入 noTx()(没有 @Transactional):事务活跃=false
放在线程上,事务外同步是关闭的、没有绑定资源。