事务状态存在哪里?提交前后各个回调谁先谁后?afterCommit 里抛异常会怎样?为什么子线程、自己拿的连接都不在事务里?这篇在 Spring Framework 7.0.9 和 MySQL 26.7.0 上逐项验证。
--- @Transactional(isolation = READ_COMMITTED) 方法里 1. isSynchronizationActive=true,isActualTransactionActive=true 2. 事务名=Svc.inspect,隔离级别=2(2 = READ_COMMITTED),只读=false 3. 线程上绑定的资源:键 HikariDataSource → 值 ConnectionHolder,持有连接 HikariProxyConnection 4. 已注册的同步器数:0(JdbcTemplate 之类的在需要时注册) --- 事务外 1. 事务外 isSynchronizationActive=false,资源 0 个
事务名、隔离级别、只读标志和 ConnectionHolder 都绑在当前线程上。
--- 正常提交 1. 方法体里 2. beforeCommit(readOnly=false) 3. beforeCompletion() 4. afterCommit():事务已经提交了,但连接还没还给连接池 5. afterCompletion(status=COMMITTED) --- 回滚 1. 方法体里 2. beforeCompletion() 3. afterCompletion(status=ROLLED_BACK) 4. 调用者收到 IllegalStateException --- afterCommit 里抛异常(方法本身成功) 1. 方法体里 2. beforeCommit(readOnly=false) 3. beforeCompletion() 4. afterCommit():事务已经提交了,但连接还没还给连接池 5. afterCompletion(status=COMMITTED) 6. 调用者收到 IllegalStateException: afterCommit 里抛异常;表里行数 2
提交与回滚的回调不同,afterCommit 抛异常撤销不了提交。
--- 事务线程与子线程 1. 主线程 isActualTransactionActive=true,资源 1 个;子线程 isActualTransactionActive=false,资源 0 个
子线程里事务不活跃,没有资源。
--- 在 @Transactional 里自己拿连接写入 1. 直接 ds.getConnection():得到的连接 id 16,事务连接 id 15(不同的连接) 2. 方法抛了异常之后,表里有 1 行(0 表示 insert 跟着回滚了) 3. 经 TransactionAwareDataSourceProxy:得到的连接 id 15,事务连接 id 15(同一个连接) 4. 方法抛了异常之后,表里有 0 行(0 表示 insert 跟着回滚了)
直接 ds.getConnection() 不在事务里,TransactionAwareDataSourceProxy 能让它加入。