MySQL乐观锁、共享锁、排他锁、行锁、表锁区别和使用方法
數(shù)據(jù)庫鎖分類
| 范圍鎖 | 行鎖、表鎖 |
| 算法鎖 | 臨間鎖、間隙鎖、記錄鎖 |
| 屬性鎖 | 共享鎖(讀鎖)、排他鎖(寫鎖) |
| 狀態(tài)鎖 | 意向共享鎖、意向排他鎖 |
?
一、樂觀鎖和悲觀鎖
1.樂觀鎖介紹
樂觀鎖( Optimistic Locking ) 相對悲觀鎖而言,樂觀鎖假設(shè)認(rèn)為數(shù)據(jù)一般情況下不會造成沖突,所以在數(shù)據(jù)進(jìn)行提交更新的時候,才會正式對數(shù)據(jù)的沖突與否進(jìn)行檢測,如果發(fā)現(xiàn)沖突了,則讓返回用戶錯誤的信息,讓用戶決定如何去做。那么我們?nèi)绾螌崿F(xiàn)樂觀鎖呢,一般來說有以下2種方式:
2.使用方法
版本號控制
版本號的實現(xiàn)方式有兩種,一個是數(shù)據(jù)版本機(jī)制,一個是時間戳機(jī)制。具體如下。
a.使用數(shù)據(jù)版本(Version)記錄機(jī)制實現(xiàn),這是樂觀鎖最常用的一種實現(xiàn)方式。何謂數(shù)據(jù)版本?即為數(shù)據(jù)增加一個版本標(biāo)識,一般是通過為數(shù)據(jù)庫表增加一個數(shù)字類型的 “version” 字段來實現(xiàn)。當(dāng)讀取數(shù)據(jù)時,將version字段的值一同讀出,數(shù)據(jù)每更新一次,對此version值加一。當(dāng)我們提交更新的時候,判斷數(shù)據(jù)庫表對應(yīng)記錄的當(dāng)前版本信息與第一次取出來的version值進(jìn)行比對,如果數(shù)據(jù)庫表當(dāng)前版本號與第一次取出來的version值相等,則予以更新,否則認(rèn)為是過期數(shù)據(jù)。
3.代碼實現(xiàn)
數(shù)據(jù)庫表新增字段version,更新修改操作時,需要比較當(dāng)前版本值是否相等,相等的話,每次修改值時,將版本號version+1,同一版本的數(shù)據(jù)只能有一次提交成功,其他提交時會因為version不一致導(dǎo)致修改失敗
<update id="updateGoodsUseCAS" parameterType="Goods"> ?<![CDATA[?update t_goods?set status=#{status},name=#{name},version=version+1?where id=#{id} and version=#{version}?]]> ? </update> ?二、屬性鎖
MySQL常用引擎有MyISAM和InnoDB,而InnoDB是mysql默認(rèn)的引擎。MyISAM不支持事務(wù),InnoDB支持事務(wù)。MyISAM不支持行鎖,而InnoDB支持行鎖和表鎖。MyISAM在執(zhí)行查詢語句(SELECT)前,會自動給涉及的所有表加讀鎖,在執(zhí)行更新操作(UPDATE、DELETE、INSERT等)前,會自動給涉及的表加寫鎖,這個過程并不需要用戶干預(yù),因此用戶一般不需要直接用LOCK TABLE命令給MyISAM表顯式加鎖
1.共享鎖(讀鎖)
共享 (S) 用于不更改或不更新數(shù)據(jù)的操作(只讀操作),多個事務(wù)對同一數(shù)據(jù)共享一把鎖。 如 SELECT 語句。如果事務(wù)T對數(shù)據(jù)A加上共享鎖后,則其他事務(wù)只能對A再加共享鎖,不能加排他鎖。獲準(zhǔn)共享鎖的事務(wù)只能讀數(shù)據(jù),不能修改數(shù)據(jù)。
顯示加鎖:
select * from t_activity where id=1 lock in share mode;2.排他鎖(寫鎖)
用于數(shù)據(jù)修改操作,例如 INSERT、UPDATE 或 DELETE。確保不會同時同一資源進(jìn)行多重更新。如果事務(wù)T對數(shù)據(jù)A加上排他鎖后,則其他事務(wù)不能再對A加任何類型的鎖,包括共享鎖和排它鎖。獲準(zhǔn)排他鎖的事務(wù)既能讀數(shù)據(jù),又能修改數(shù)據(jù)。類似于資源鎖,只允許一個請求進(jìn)來。
select * from t_activity where id=1 for update;如下所示:innodb引擎對select開啟事務(wù),id為1的數(shù)據(jù)使用排它鎖,事務(wù)沒有結(jié)束時,其他事務(wù)不能獲取到排它鎖,提交之后就可以了
(1)可視化界面事務(wù)中使用排它鎖,命令行事物對同一行數(shù)據(jù)也獲取排它鎖
(2)事務(wù)中使用排它鎖,其他事物對同一行數(shù)據(jù)獲取共享鎖
(3)事務(wù)中使用排它鎖,提交之后,其他事物對同一行數(shù)據(jù)也獲取排它鎖
mysql InnoDB引擎默認(rèn)的修改數(shù)據(jù)語句,update,delete,insert都會自動給涉及到的數(shù)據(jù)加上排他鎖,select語句默認(rèn)不會加任何鎖類型
三、范圍鎖
行鎖和表鎖其實是排它鎖的兩種實現(xiàn),主要用于update,delete,insert這些語句,區(qū)別在于是對是否命中索引
1.行鎖
行鎖就是鎖一行或者多行記錄,mysql的行鎖是基于索引加載的,所以行鎖是要加在索引響應(yīng)的行上,即命中索引
這里的表t_activity中id是主鍵索引,在事務(wù)中沒有結(jié)束的情況下,命中索引,進(jìn)行修改操作,其他事務(wù)對同一張表中的相同數(shù)據(jù)不能進(jìn)行修改,必須等待事務(wù)提交完畢,釋放了行鎖,才能執(zhí)行。
t_activity表數(shù)據(jù)如下所示,id為主鍵索引,credit未添加索引
可視化界面中開啟事務(wù),修改表t_activity 的id為6的credit為10,命令行中一事物修改id為6的credit為8,因為是同一行數(shù)據(jù),事務(wù)未提交,行鎖沒有釋放,無法進(jìn)行修改 。
可視化界面中開啟事務(wù),修改表t_activity中id=1的credit字段,不關(guān)閉事務(wù),命令行一事物修改id=2的credit為8,成功,兩者互不影響,因為行鎖只鎖定了id=1的這一行,id為2的這一行沒有鎖住,可以正常執(zhí)行
2.表鎖
表鎖就是一鎖鎖一整張表,在表被鎖定期間,其他事務(wù)不能對該表進(jìn)行操作,必須等當(dāng)前表的鎖被釋放后才能進(jìn)行操作。表鎖響應(yīng)的是非索引字段,即全表掃描,全表掃描時鎖定整張表,sql語句可以通過執(zhí)行計劃看出掃描了多少條記錄。
這里在可視化界面事務(wù)中對t_activity表中非索引字段進(jìn)行修改,命令行事務(wù)中任意修改表數(shù)據(jù),會導(dǎo)致修改失敗,因為鎖定了整張表
事務(wù)提交完畢后,釋放了表鎖,其他事物就可以修改表中任意數(shù)據(jù)了
總結(jié)
以上是生活随笔為你收集整理的MySQL乐观锁、共享锁、排他锁、行锁、表锁区别和使用方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring 通过Java Config
- 下一篇: Redis Lua脚本实现原子性操作