差点就让我背上了一个 P0 事故!
|
ps:看到上面的语序,有没有个小问号?为什么相同查询了这么多次? 其实这些 SQL 语序并不在同个方法内,并且有些方法被抽出复用,所以导致一些相同查询结果没办法往下传递,所以只得再次从数据库中查询。 为了防止并发更新余额,在 t3 时刻,使用写锁锁住该行记录。若加锁成功,其他线程的若也执行到 t3,将会被阻塞,直到前一个线程事务提交。 t5 时刻,进入到下一个方法,再次获取账户余额,然后在 Java 方法内比较余额与扣减金额,若余额充足,在 t7 时刻执行更新操作。 上面的 SQL 语序看起来没有什么问题吧,实际也是这样的,账户系统已经在生产运行很久,没出现什么问题。但是这里需要说一个前提,系统数据库是 Oracle 。 但是从上面表结构,可以得知此次数据库被切换成 MySQL,系统其他任何代码以及配置都不修改(sql 存在小改动)。 就是这种情况下,并发执行发生余额多扣,即实际余额明明小于扣减金额,但是却做了余额更新操作,最后导致余额变成了负数。 下面我们来重现并发这种情况,假设有两个事务正在发执行该语序,执行顺序如图所示。
注意点:数据库使用的是 MySQL,默认事务隔离等级,即 RR。数据库记录为 id=1 balance=1000,假设只有当时只有这两个事务在执行。 (编辑:孝感站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |

