Mysql事务并发问题解决方案
作者:手撕高达的村长
在开发中遇到过这样一个问题
一个看视频记录,更新到100就表示看完了,后面再有请求不继续更新了.
结果是:
导致,里面很多数据出现问题.
推测是以下的情况才会导致
第一条请求 事务在执行中,还未提交(因为本地有时候比较难再现,于是手动在程序中,第一条记录处理的时候,sleep了几秒,就达到这种效果了)
第二条请求 事务已经开始执行,这个时候查到的历史最大值不是100,才会去进行了更新
网上看了一下解决方案:
悲观锁
直接锁行记录
这个我在本地测试,确实有效,一个事务开始没结束,第二个事务一个等待,不过会导致处于阻塞状态,因为系统并发,不敢考虑,也就是记录下这个方式.
手动模拟:
执行第一个事务:
-- 视频100BEGIN; SELECT * FROM `biz_coursestudyhistory` WHERE sid = 5777166; UPDATE biz_coursestudyhistory set studyStatus = 100,versionNO=versionNO+1 WHERE sid = 1 AND versionNO = 0; -- commit ; 先不执行,先注解掉,只执行上面的
接着执行第二个事务:
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;
会发现成功不了,一直处于等待状态.
查看锁
确实被锁住了,这里只要执行第一个事务的commit ,第二个事务就会执行.
从这里可以看出,行锁可以直接达到理想的数据统一状态,一个事务修改,其他都不能操作,感觉这种比较适合银行这种安全性的项目
乐观锁:
这种比较简单,并且不会造成阻塞
方式就是加上版本号
var maxver = select max(version) from table
更新的话使用
update table set studystatus = xxx,version = version +1 where id =1 and version = maxver
写入的话
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进行多线程测试,从最开始的多条记录更新成功,变成只有一个成功,后面的失败.
从最开始的插入多条记录,到后来的只能插入一条数据了
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。