概述
昨晚2021年2月22日功能上线的时候,故障群里突然大面积保障,订单无法展示了。由于影响范围比较广,立刻让运维把服务回滚回去,10分钟后,故障消失了。
接下来开始找故障的根因,最后发现原来是事务问题导致,日志里提示了如下一个错误:
Transaction rolled back because it has been marked as rollback-only
意思是,准备提交事务,将落地的数据库数据生效时,事务已经被设置为rollback-only
了,无法提交事务。后面仔细看了一下代码,原来是开了事务的方法里,抛了一个异常,但是程序把这个异常给catch
住了,没往上抛。
@Transactional(rollbackFor = Exception.class)
public void open() {
try{
//这里某段代码抛异常了,但是被catch住了。
}
catch(Exception e) {
}
//其他业务逻辑代码
}
这个open
方法里的某段代码抛出异常了,这里Spring
已经将事务设置为rollback-only
了,但是由于异常被catch
住了,当线程执行完open
方法后,就会开始提交事务,然后发现压根无法提交事务。
这里有个教训:
业务逻辑必须是一个事务,一起生一起死的,就放在一块,否则将对应的代码移到事务外。
小结
有时候你可能是想通过catch
异常的方式,保护主流程代码,但是由于事务问题,好心做坏事了。