在开发中遇到过这样一个问题
一个看视频记录,更新到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进行多线程测试,从最开始的多条记录更新成功,变成只有一个成功,后面的失败.
从最开始的插入多条记录,到后来的只能插入一条数据了
您可能感兴趣的文章:MySQL并发更新数据时的处理方法Tomcat+Mysql高并发配置优化讲解PHP利用Mysql锁解决高并发的方法PHP+MySQL高并发加锁事务处理问题解决方法分析MySQL并发下的问题及解决方法Yii+MYSQL锁表防止并发情况下重复数据的方法MySQL中实现高性能高并发计数器方案(例如文章点击数)MySQL中SELECT+UPDATE处理并发更新问题解决方案分享利用mysql事务特性实现并发安全的自增ID示例深入mysql并发插入优化详解