乐观锁+版本号解决锁竞争问题

乐观锁+版本号解决锁竞争问题

在高并发的场景下,经常会遇到这种情况:
A请求过来,查询出来一条数据,进行update操作,与此同时B请求也在这个时候过来,对这条数据进行查询,并进行操作。此时就会出现B在A之后进行查询操作,但是实际B的数据却被A覆盖。

这种情况并不少见,有时候会为了避免这种情况,我们会引入锁来解决这种问题,常见的比如使用ReetrantLock或者synchronized同步块等悲观锁的方式来实现,其实在这里,我们也可以尝试使用乐观锁+版本号的方式来进行处理。

可以举个更具体的案例来说明一下。
A请求

select num from store where id='1';

此时获取到num=99

这时候B请求进来后,也发起查询

select num from store where id='1';

此时由于A请求尚未进行update,B请求获取到的num也等于99。
这时候A进行update操作

update store set num =${num} +1 where id='1';

这时候写入数据库的num即为100
此时B请求也发起了更新操作:

update store set num =${num} +1 where id='1';

这时候我们的预期本应该是101的,但是实际上B又在数据库写入了100.

解决方案:
这时候我们可以引入一个版本号的概念,来巧妙的解决这个问题。

A请求

select num,version from store where id='1';

此时假设num=99,version=1,这时候B依然发起select请求:

select num,version from store where id='1';

没有意外,B取到的version也是1,这时候A进行update写入,此时:

update store set num =${num} +1,version=${version}+1 where id='1' and version='1'

由于A进行行级锁,此时version也变成了2。
B这时候发起操作,由于select的时候,版本号依然为1,此时实际B无法进行update的

update store set num =${num} +1,version=${version}+1 where id='1' and version='1'

我们可以看到由于在数据库的版本号已经变成2,了,实际version=1会让B请求的更新数据不能成功。

原文地址:https://www.cnblogs.com/lqmblog/p/13745213.html