事务挂起本质是事务开启后未正常提交或回滚,导致锁和连接长期占用。根本原因包括Spring对受检异常默认不回滚、事务内启新线程、远程调用无超时、try-catch吞异常未设rollbackOnly等,需结合应用日志、数据库会话状态(如idle in transaction)、JVM线程堆栈协同排查。

线上事务挂起(Transaction Hang)通常表现为数据库连接长时间占用、SQL 执行卡住、接口响应超时,但无明显异常日志。根本原因往往是事务未正常提交或回滚,导致数据库锁未释放、连接被占、后续请求阻塞。排查需从应用层、框架层、数据库层协同分析。
看 Spring 事务传播行为和异常处理是否匹配
Spring 默认 只对 RuntimeException 和 Error 回滚,若业务抛出受检异常(如 IOException、SQLException),事务不会自动回滚,但方法执行完后事务仍处于“活跃挂起”状态(尤其在 PROPAGATION_REQUIRED 下),连接不释放。
- 检查 service 方法是否声明了
@Transactional(rollbackFor = Exception.class) - 确认是否有 try-catch 吞掉了异常却没手动调用
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly() - 避免在事务方法内开启新线程(如
new Thread(...).start()),子线程无法继承事务上下文,主线程事务可能因等待而挂起
查数据库连接和锁状态,定位物理阻塞点
事务挂起最终会反映在数据库侧:长事务持有行锁/表锁、连接空闲但事务未结束、会话处于 idle in transaction 状态。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- PostgreSQL:执行
SELECT * FROM pg_stat_activity WHERE state = 'idle in transaction';查看挂起事务及其 SQL 和等待事件 - MySQL:查
SHOW PROCESSLIST;中Command=Sleep且Time很大,再结合information_schema.INNODB_TRX看TRX_STATE='RUNNING'但TRX_STARTED时间异常久 - Oracle:查
V$SESSION中STATUS='ACTIVE'且SQL_ID为空,或V$TRANSACTION中START_TIME过早
抓取 JVM 线程快照,确认事务边界是否卡在某处
事务挂起常伴随线程阻塞(如等待锁、IO、远程调用),通过线程堆栈可判断事务是否“卡在中间”。
立即学习“Java免费学习笔记(深入)”;
- 用
jstack -l <pid> > jstack.log抓当前线程快照,搜索org.springframework.transaction或DataSourceUtils相关栈帧 - 重点关注线程状态为
WAITING或BLOCKED,且栈顶是Connection.prepareStatement、JdbcTransaction.doBegin、或远程调用(如 Feign、Dubbo)未返回 - 对比多个时间点的 jstack,若同一事务相关线程始终停在相同位置,大概率是下游依赖超时未处理,导致事务无法退出
启用 Spring 事务调试日志,观察生命周期
打开 DEBUG 级别日志可清晰看到事务创建、挂起、恢复、提交/回滚全过程,快速识别“有 begin 无 commit/rollback”。
- 在
application.yml中添加:
logging:
level:
org.springframework.transaction: DEBUG
org.springframework.jdbc.datasource: DEBUG - 典型挂起线索:
日志出现Creating new transaction,但后续无Initiating transaction commit或Initiating transaction rollback
或出现Participating in existing transaction后长期静默 —— 表明外层事务已挂起,内层只是加入

















