Mysql事务并发问题解决方案

时间:2021-07-11 22:30:11

在开发中遇到过这样一个问题

一个看视频记录,更新到100就表示看完了,后面再有请求不继续更新了.

结果是:

Mysql事务并发问题解决方案

导致,里面很多数据出现问题.

推测是以下的情况才会导致

第一条请求 事务在执行中,还未提交(因为本地有时候比较难再现,于是手动在程序中,第一条记录处理的时候,sleep了几秒,就达到这种效果了)

第二条请求 事务已经开始执行,这个时候查到的历史最大值不是100,才会去进行了更新

网上看了一下解决方案:

悲观锁

直接锁行记录

这个我在本地测试,确实有效,一个事务开始没结束,第二个事务一个等待,不过会导致处于阻塞状态,因为系统并发,不敢考虑,也就是记录下这个方式.

手动模拟:

执行第一个事务:

?
1
2
3
4
5
6
7
-- 视频100begin;
 
select * from `biz_coursestudyhistory` where sid = 5777166;
 
update biz_coursestudyhistory set studystatus = 100,versionno=versionno+1 where sid = 1 and versionno = 0;
 
-- commit ; 先不执行,先注解掉,只执行上面的

Mysql事务并发问题解决方案

接着执行第二个事务:

?
1
2
3
4
5
6
7
begin;
 
update biz_coursestudyhistory set studystatus = 90,versionno=versionno+1 where sid = 1 and versionno = 0;
 
select * from `biz_coursestudyhistory` where sid = 1 for update;
 
commit;

会发现成功不了,一直处于等待状态.

查看锁

Mysql事务并发问题解决方案

确实被锁住了,这里只要执行第一个事务的commit ,第二个事务就会执行.

从这里可以看出,行锁可以直接达到理想的数据统一状态,一个事务修改,其他都不能操作,感觉这种比较适合银行这种安全性的项目

乐观锁:

这种比较简单,并且不会造成阻塞

方式就是加上版本号

var maxver = select max(version) from table

更新的话使用

update table set studystatus = xxx,version = version +1 where id =1 and version = maxver

写入的话

?
1
2
3
4
insert into table (contentstudyid,coursewareid,studystatus,studytime,endtime)
select 27047358,3163,100,333,now() from dual where not exists (select 1 from table where contentstudyid =27047358 and
coursewareid = 3163
 )

这种方式,可以在更新或者写入的时候,直接判断库里面存在的数据是否存在,如果不存在则是别其他的线程使用了.

修改为这种写法后,使用jmeter进行多线程测试,从最开始的多条记录更新成功,变成只有一个成功,后面的失败.

从最开始的插入多条记录,到后来的只能插入一条数据了

Mysql事务并发问题解决方案

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://www.cnblogs.com/sunxun/p/13092874.html