日常Bug排查-应用Commit报错事务并没有回滚

Posted alchemystar

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了日常Bug排查-应用Commit报错事务并没有回滚相关的知识,希望对你有一定的参考价值。

日常Bug排查-应用Commit报错事务并没有回滚

前言

日常Bug排查系列都是一些简单Bug排查,笔者将在这里介绍一些排查Bug的简单技巧,同时顺便积累素材_

应用Commit报错并不一定回滚

事实上,这篇文章并没有什么排查过程。但这个问题却又是笔者经常遇到的。
笔者仅仅是想阐述一下当我们在事务Commit报错时候,数据库中的数据并不一定会是我们以为的回滚状态。笔者举个例子:

在这种情况下,很明显的DB的数据肯定是处于已经提交的状态。而如果App认为是回滚状态,并基于这个信息去做操作的话,很明显会导致数据不一致。

非IO or 超时异常 也不一定回滚

可能有人会问了,是不是仅仅是IO异常或者超时异常才会出现这种不一定回滚的问题呢?这里还真不一定,笔者在一次Case中,就发现Oracle在commit的时候返回死锁异常时候,数据库内部的commit竟然也成功了!这就牵涉到数据库内部的处理了。

应用应该怎么做呢?

事实上,由于数据库保证了原子性。所以我们在遇到这种情况时候,需要从数据库中重建状态,而不是依赖现在应用里面的信息。所以遇到异常直接将流程结束,然后等定时任务等补单操作是个比较简单安全的做法。
当然,数据库中重建状态时候,也要考虑到上一个相应的commit还在commit的过程中,只不过这个commit非常慢而已。由于我们更新数据或者最终判断的时候往往会锁住数据,而数据库一般都是采用了二阶段锁(S2PL)。

在上一个commit成功提交之后,我们对相应数据的操作才会执行下去。所以只要小心的控制好锁的范围,数据一致性还是能保证的。

总结

Commit报错但事务并没有回滚,这个虽然有点反直觉,但这确是在产线真实存在的,尤其在数据库压力大的时候极易出现。这个坑在我们编写代码的时候需要牢记!

以上是关于日常Bug排查-应用Commit报错事务并没有回滚的主要内容,如果未能解决你的问题,请参考以下文章

二分法如何排查问题版本

Spring事务管理中的配置文件

mysql存储过程中最后有commit和没有commit 是有所不同的。(为测试但是碰到过这个问题)

mysql中innodb数据库事务修改多记录

事务提交抛出异常:事务设置为仅回滚

为什么加了@Transactional注解,事务没有回滚?