乐观锁解决数据并发冲突
一 为什么会产生并发冲突
我们来看一个例子:
我们都知道,这个过程每次单独处理是没有问题的,但是一般情况下,在业务操作的过程中,可能我过程1没有结束,过程2就开始进行了,此时数据就不是之前的数据,如上图,理论我需要的结果是 400+100,完成后,再500+500=1000,实际可能我过程2得到的结果是900。
我们来看以前传统的解决方案是如何开启悲观锁的:
手动在sql后边加for update,开启行锁。
悲观锁可以实现这个功能,但是其存在的觉点就是性能实在是太差。
可能会有人说,这个账户就是某个人的,应该不存在很高的并发,但是你想,如果这是一个结算的账户,那么他需要的并发就肯定很高。
那我们需要实现什么样的目标呢?
二 乐观锁的实现
乐观锁的实现是需要我们程序进行设计的,如下:
id | bal | _version |
---|---|---|
1001 | 400 | 1 |
我们在表上设计一个_version的版本号,其现在的流程就会变成下边的样子:
我们在更新该条数据的时候,获取其值的同时,需要获取其版本号,然后在更新的时候,仅针对当前版本号做更新,同时更新其版本号。
假如当前版本号已被更新,版本号对不上,就需要重新去获取当前的数据,在更新的数据上进行更新。
按照以上的逻辑,其实我们在过程2时,发现版本号不一致,更新其实是不会成功的,保证了数据的安全,但是当前过程却被作废了,那么,如何解决这种数据冲突的问题呢?
首先解决方法一,前端友好提示:
- 前端应用提示“数据正在处理,请稍后再试!”
另外的解决方案就是在代码重试:
- 附加spring-retry在service上进行方法重试
如图:
但是这里要注意,更新结果返回0,不一定是并发问题,有可能是数据没有更新,就是本次更新与上次更新一致,但是我们更新了版本,所以不用太担心。