如何解决hibernate的autoFlush机制造成的父子事务死锁问题

背景:订单处在等待第三方回调的阶段,需要等待多个第三方全部回调完成后拉起订单往下执行。此时现网出现部分异常订单,所有第三方回调以后订单仍然不继续执行。拉取现网当天的日志后发现父事务超过最大时间限制,自动销毁,导致回调进程结束。

查看日志与走读代码,发现超时的父事务中存在两个独立子事务,这两个子事务中存在两次更新订单表状态的操作,但是阅读日志发现存在三次更新表语句,原来是因为hibernate的autoFlush机制导致父事务中查询订单表时也生成了一次update语句:

恰恰是这次update语句导致父事务将订单表锁住了,而这个锁操作只有在父事务结束时才会释放。但是问题就出在了接下来的独立子事务中又更新了订单表状态,那么在子事务B结束尝试提交时就会陷入死锁,一直等到父事务最大等待时间到了之后整个进程结束,订单卡死。

那么,为什么父事务会生成一条update语句呢?

在hibernate中,默认的提交机制为auto-flush,也就是在事务结束或查询时会检查Session中的实体对象和数据库中的实体对象是否一致,如果不一致则提交update或insert语句。在我们这个场景中,由于父子事务共享的是一个hibernate的session,所以子事务更新订单表实例后也同时更新了共享session中的订单实例(脏数据),所以在父事务中查询时识别到这个是脏数据就生成了update语句。最终导致了后面的问题。

要解决这个问题,有三种方案。第一是将父子事务的session隔离,这样做的坏处是由于没有共享session查询效率会降低。第二种方案则是将两个独立事务都合并到父事务中变成一个事务,但是这个会导致如果中间执行失败,会回滚所有更新语句,导致状态丢失。第三种则是将hibernate的提交机制改为FlushMode.COMMIT:仅事务结束时或FlushMode.MANUAL:必须显式调用 flush(),来避免auto-flush生成的update语句。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值