transactiontemplate控制高并发锁耗时的核心是仅对关键db操作启用事务,将oss上传、校验等非一致性逻辑移出事务;需显式设置传播行为、隔离级别与超时,并配合select for update或乐观锁解决查改分离问题;回调须在aftercommit中异步执行。

用 TransactionTemplate 控制高并发下的锁持有耗时,核心是把“真正需要数据库一致性保障”的操作单独包裹进事务,而把耗时但不涉及数据一致性的逻辑(如HTTP调用、文件上传、缓存操作)移出事务边界。这样能大幅缩短行锁、表锁的持有时间,避免连接池耗尽和锁竞争加剧。
只在关键DB操作上启用事务
事务不是越早开启越好,而是越晚开启、越快结束越好。比如一个订单编辑接口要上传富文本图片到OSS、更新服务主表、同步关联项目数据——只有后两者必须原子执行,前者完全可前置处理。
- 先完成所有非DB操作:OSS上传、参数校验、DTO转换等
- 再用
transactionTemplate.execute()包裹真正的数据库写操作(如updateById、deleteByXXX、insertBatch) - 确保事务块内没有日志打印、远程调用、循环计算等无关代码
显式指定事务属性,避免默认行为拖累性能
TransactionTemplate 支持动态设置传播行为、隔离级别和超时时间,这对高并发场景至关重要。
- 用
PROPAGATION_REQUIRED保证嵌套调用仍处于同一事务上下文(如内部 service 方法复用) - 对读多写少且允许脏读的场景,可设为
ISOLATION_READ_COMMITTED(MySQL 默认),避免REPEATABLE_READ的间隙锁放大锁范围 - 务必设置
setTimeout(3)(单位秒),防止某次异常阻塞导致锁长期不释放
配合数据库锁机制,堵住并发漏洞
@Transactional 再细粒度也解决不了“查-改”分离导致的超卖问题。TransactionTemplate 同样需要搭配数据库锁使用。
- 在事务块内执行查询时,改用
SELECT ... FOR UPDATE或 JPA 的@Lock(LockModeType.PESSIMISTIC_WRITE) - 避免先查再 update 的两步模式,尤其在库存、优惠码、账户余额等热点数据场景
- 若业务允许,也可用乐观锁(如 version 字段 + CAS 更新),减少数据库锁开销
注意回调与异常处理的边界
TransactionTemplate 允许注册 TransactionSynchronization,用于提交后刷新缓存、发MQ消息等,但这些操作绝不能放在事务块内。
- 事务成功提交后,通过
afterCommit()触发异步动作,不延长锁时间 - 捕获异常时,用
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()主动标记回滚,避免部分更新残留 - 不要在 execute 回调里 try-catch 吞掉业务异常,否则事务可能意外提交











