DataSourceTransactionManager的doBegin方法在何种场景下不会创建新连接?
DataSourceTransactionManager的doBegin方法在何种场景下不会创建新连接?
这个问题我刚接触Spring事务的时候也纠结过,咱们先盯着doBegin里的判断条件看:
if (!txObject.hasConnectionHolder() || txObject.getConnectionHolder().isSynchronizedWithTransaction()) { // 创建新连接的逻辑 }
只有当这个条件不成立时,才会跳过新连接创建,复用现有连接。换句话说,必须同时满足以下两个条件:
txObject已经持有一个ConnectionHolder对象- 这个
ConnectionHolder的isSynchronizedWithTransaction()返回false
那具体是什么业务场景会触发这种情况呢?最典型的就是:当前线程中已经存在一个被绑定的数据库连接,但这个连接还没有被关联到任何事务。
举个实际代码例子:
// 在事务外,通过Spring的DataSourceUtils获取连接,此时连接会被绑定到当前线程 Connection con = DataSourceUtils.getConnection(dataSource); // 此时TransactionSynchronizationManager中已经存在这个连接对应的ConnectionHolder,但它的isSynchronizedWithTransaction是false // 接下来开启一个事务(比如默认的PROPAGATION_REQUIRED) transactionTemplate.execute(status -> { // 这里触发doBegin时,会复用上面已经存在的连接,而不是新建 jdbcTemplate.update("INSERT INTO user(name) VALUES (?)", "test"); return null; });
为什么Spring要这么设计?
核心是减少连接池的开销——如果线程已经持有一个可用的连接,没必要再从连接池里申请新的,避免不必要的连接创建和销毁成本。
你担心的“修改外部连接状态”问题,Spring已经兜底了
你提到的比如把autocommit设为false、修改隔离级别这些操作,Spring都会在事务启动前仔细记录原来的状态:
- 用
previousIsolationLevel保存连接原来的隔离级别 - 用
mustRestoreAutoCommit标记原来的autocommit状态
等事务结束后,在doCleanupAfterCompletion方法中,Spring会自动恢复这些状态:把autocommit改回原来的值,隔离级别也恢复成之前的设置,完全不会影响外部对这个连接的后续使用。
补充:和事务传播行为的区别
你提到的外部事务场景,比如使用PROPAGATION_REQUIRES_NEW时,Spring会通过suspend方法挂起外部事务的ConnectionHolder,此时新事务会创建新连接。但如果是没有外部事务,只是线程已经预先持有一个未绑定事务的连接,就会触发复用逻辑。
总结一下,复用连接的核心场景就是:线程预先持有了未关联事务的数据库连接,此时开启事务会直接复用该连接,而非新建。
备注:内容来源于stack exchange,提问作者user29728765
相关产品推荐
相关产品推荐

