Mysql鎖機制--悲觀鎖和樂觀鎖


1. 悲觀鎖簡介

  悲觀鎖(Pessimistic Concurrency Control,縮寫PCC),它指的是對數據被外界修改持保守態度,因此,在整個數據處理過程中, 將數據處於鎖定狀態。悲觀鎖的實現,往往依靠數據庫提供的鎖機制,也只有數據庫層提供的鎖機制才能真正保證數據訪問的排他性,否則,即使在本系統中實現了加鎖機制,也無法保證外部系統不會修改數據。

2. 悲觀鎖舉例(MySQL InnoDB為例)

  商品表t_goods中有字段status標識商品的狀態,0標識未售出,1標識已售出。當用戶生產訂單時,該商品的status必須為0則認為是有效訂單。

1 create table t_goods (id int(11) primary key auto_increment, name varchar(255), status int(1) default 0);
2 insert into t_goods (name) value ('手機');
3 select * from t_goods;
4 
5 create table t_orders (id int(11) primary key auto_increment, goods_id int(11));

  假如不添加鎖,則順序為:

# 1.查詢商品
select * from t_goods where id  = 1 and status  = 0;
# 2.生產訂單
insert into t_orders (goods_id) value (1);
# 3.更新狀態
update t_goods set status = 1 where id = 1;

select * from t_goods;

  這種情況在單線程或只有一個用戶使用時沒有問題,但是在多線程或並發場景下是不安全的。

  若在更新前,有其他訂單提前將狀態更新為1,則商品被重復下單,造成數據不一致的情況。

  使用悲觀鎖實現,則順序為:

 1 #必須關閉Mysql數據庫的自動提交屬性
 2 #因為Mysql默認使用autocommit模式,即執行更新操作后,Mysql會立刻提交結果
 3 
 4 show variables like '%autocommit%';
 5 #臨時設置
 6 set autocommit  = 0;
 7 
 8 # 1.開啟事務(begin; begin work; start transaction;)
 9 begin;
10 # 2.查詢商品
11 select * from t_goods where id  = 1 and status  = 0 for update;
12 # 3.生產訂單
13 insert into t_orders (goods_id) value (1);
14 # 4.更新狀態
15 update t_goods set status = 1 where id = 1;
16 # 5.提交事務(commit; commit work;都可以)
17 commit;
18 
19 select * from t_goods;

  使用select * from tbale_name for update實現了悲觀鎖,即對id=1的數據進行加鎖,其他事務對該數據的操作會進行阻塞,當前事務提交后,才允許其他事務對其進行操作。

  注意:當開始一個事務,執行select * from tbale_name for update,在另外事務中select ...for update時會阻塞,但是使用select * from tbale_name 則不會阻塞。

  select ... for update詳解:Mysql的InnoDB引擎默認使用Row-Level Lock(行級鎖),因此在查詢中要指定主鍵,否則,Mysql會執行Table-Level Lock(表級鎖)。

 1 #分別在兩個窗口執行
 2 # 1. 指定主鍵,並且主鍵存在,row lock
 3 select * from t_goods where id = 1 for update;
 4 # 2. 指定主鍵,主鍵不存在,no lock
 5 select * from t_goods where id = 999 for update;
 6 # 3. 無主鍵,table lock
 7 select * from t_goods where name = '電腦' for update;
 8 # 4. 主鍵不明確,table lock
 9 select * from t_goods where id > 10 for update;
10 select * from t_goods where id != 1 for update;
11 # 5. 指定索引,並且索引存在,row lock
12 select * from t_goods where status = 1 for update;
13 # 6. 指定索引,索引不存在,no lock
14 select * from t_goods where status = 999 for update;

3. 樂觀鎖簡介

  樂觀鎖(Optimistic Locking,簡寫PL),相對悲觀鎖而言,樂觀鎖認為數據一般情況下不會造成沖突,所以在數據進行提交更新的時候,才會對數據的沖突與否進行檢測,如果發現沖突了,則讓返回錯誤信息,讓用戶處理。

4. 樂觀鎖舉例

  使用數據版本(Version)記錄機制實現。這是樂觀鎖最常用的一種實現方式。即為數據增加一個版本標識,即增加一個數字類型的 “version” 字段。當讀取數據時,將version字段的值一同讀出,數據每更新一次,對version值加一。當提交更新時,判斷數據庫表對應記錄的當前version值與取出來的version值進行比對,如果數據庫表當前version值與取出來的version值相等,則執行更新,否則不更新。

  Mybatis Plus中提供了完整的樂觀鎖機制:https://mp.baomidou.com/guide/optimistic-locker-plugin.html#主要適用場景


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM