TransactionSystemException是Spring事务的包装异常,真实根因需通过getCause()获取,常见为SQLException、连接异常或约束冲突;排查须打印cause、检查连接池配置、避免本类自调用,并优化SQL与事务粒度。
transactionsystemexception 本身不是根因,而是 spring 对底层事务失败的包装。排查关键不在它本身,而在它的 getcause() —— 真正的问题藏在嵌套异常里。
先看 cause:90% 是 SQLException 或连接类异常
这个异常几乎不带有效业务线索,必须打印并检查 getCause():
- 日志中务必输出
e.getCause() != null ? e.getCause().toString() : "no cause" - 常见 cause 类型:
SQLException(如 Lock wait timeout exceeded、Deadlock found)、ConnectionClosedException、CannotCreateTransactionException(连不上库)、ConstraintViolationException(唯一键冲突) - IDE 调试时直接展开异常对象,重点查看
cause字段及其完整堆栈
查连接池配置:失效连接没被及时剔除
数据库主从切换、服务重启、网络抖动后,连接池可能持有已断开的连接,事务开启时就失败:
- HikariCP 必须设置
connection-test-query=SELECT 1(MySQL)且connection-test-on-borrow=true(或启用connection-test-on-create) - Druid 需开启
test-on-borrow=true+validation-query=SELECT 1 - 别依赖
auto-commit=true—— 事务内该值会被强制覆盖,无效
警惕本类自调用:事务代理失效的静默陷阱
@Transactional 方法内部直接调用本类另一个方法,事务不会生效,后续提交时因数据不一致触发异常:
- 原因:Spring 事务靠代理实现,this.xxx() 不走代理链
- 解决方案一:把被调用方法移到另一个
@Service类,通过接口注入调用 - 解决方案二:启用
@EnableAspectJAutoProxy(expose-proxy = true),并在方法内用((UserService) AopContext.currentProxy()).otherMethod()
盯住锁与超时:InnoDB 锁等待和事务超时
MySQL 行锁等待超时(innodb_lock_wait_timeout 默认 50 秒)会返回 SQLState 40001,Spring 包装成 TransactionSystemException:
立即学习“Java免费学习笔记(深入)”;
- 查 cause 是否含
Lock wait timeout exceeded或TransactionTimedOutException - 确认业务逻辑是否存在长事务、未加索引的 where 条件、或大范围 update/delete
- @Transactional 可显式设
timeout = 60,但治标不治本;优先优化 SQL 和事务粒度


















