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 ANDcourseWareID = 3163 )
這種方式,可以在更新或者寫入的時候,直接判斷庫里面存在的數據是否存在,如果不存在則是別其他的線程使用了.
修改為這種寫法后,使用jmeter進行多線程測試,從最開始的多條記錄更新成功,變成只有一個成功,后面的失敗.
從最開始的插入多條記錄,到后來的只能插入一條數據了
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持好吧啦網。
相關文章:
1. MySQL導入sql文件的三種方法小結2. MySQL數據庫表空間回收的解決3. MySQL Threads_running飆升與慢查詢的相關問題解決4. Navicat Premium操作MySQL數據庫(執行sql語句)5. Sql Server中通過sql命令獲取cpu占用及產生鎖的sql6. 簡單了解mysql InnoDB MyISAM相關區別7. MySQL分支選擇參考:Percona還是MariaDB8. MySQL中的 inner join 和 left join的區別解析(小結果集驅動大結果集)9. sql查詢一個數組中是否包含某個內容find_in_set問題10. MySQL外鍵約束的實例講解
