关于update操做并发问题

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

表名A,字段名为 number,以下的SQL语句:sql

甲操做 语句1:select num from store where id='1';数据库

假设此时甲获取到 num= 99并发

乙操做 语句2:select num from store where id='1';ide

由于甲方尚未update操做,乙获也取到 num= 99
这时候A进行update操做高并发

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

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

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

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

解决方案:

(1)引入一个版本号的概念,在表A中增长一个version字段

甲操做 语句1:select num,version from store where id='1';

假设此时甲获取到 num= 99 version =1

乙操做 语句2:select num,version from store where id='1';

由于甲方尚未update操做,乙获也取到 num= 99 version=1
这时候A进行update操做

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

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

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

这时候发现条件version = 1不成立,由于上一步操做version已经为2了,因此update没法更新。

(2)解决方式:update A set number=number+1 where id=1; 语句直接处理

表名A,字段名为 number,以下的SQL语句:

语句1:update A set number=number+1 where id=1;
语句2:update A set number=number+2 where id=1;

假设这两条SQL语句同时被mysql执行,id=1的记录中number字段的原始值为99,那么是否有可能出现这种状况:
语句1和2由于同时执行,他们获得的number的值都是99,都是在10的基础上分别加1和2,致使最终number被更新为100或101,而不是102

这个其实就是 关系型数据库自己就须要解决的问题。首先,他们同时被MySQL执行,你的意思其实就是他们是并发执行的,而并发执行的事务在关系型数据库中是有专门的理论支持的- ACID,事务并行等理论,全部关系型数据库实现,包括Oracle, MySQL都须要遵循这个原理。简单一点理解就是锁的原理。这个时候第一个update会持有id=1这行记录的 排它锁,第二个update须要持有这个记录的排它锁的才能对他进行修改,正常的话, 第二个update会阻塞,直到第一个update提交成功,他才会得到这个锁,从而对数据进行修改。也就是说,按照关系型数据库的理论,这两个update都成功的话,id=1的number必定会被修改为22。若是不是22, 那就是数据库实现的一个严重的bug。

相关文章
相关标签/搜索