MySQL 共用鎖和排他鎖

2020-09-29 19:00:17

一、共用鎖和排他鎖

共用鎖又稱為讀鎖,簡稱D鎖,顧名思義,共用鎖就是多個事務對於同一資料可以共用一把鎖,都能存取到資料,但是隻能讀不能修改。

排他鎖又稱為寫鎖,簡稱X鎖,顧名思義,排他鎖就是不能與其他所並存,如一個事務獲取了一個資料行的排他鎖,其他事務就不能再獲取該行的其他鎖,包括共用鎖和排他鎖,但是獲取排他鎖的事務是可以對資料讀取和修改。

自己的理解


現在一個簡單的例子:

這個表進行操作
在這裡插入圖片描述

對id = 1 進行排他鎖操作,使用begin開啟事務。提交事務或回滾事務就會釋放鎖。

begin; -- 開啟事務

select * from actor where id = 1 for update; -- 進行id = 1排他鎖 

在這裡插入圖片描述

可以查詢到資料,再開啟另外一個查詢視窗。對同一資料進行排他鎖和共用鎖操作

select * from actor where id = 1 for update; -- 排他查

select * from actor where id = 1 lock in share mode; -- 共用查

-- 開了排他鎖查詢和共用鎖查詢都會處於阻塞狀態,因為id=1的資料已經被加上了排他鎖,此處阻塞是等待排他鎖釋放。
select * from actor where id = 1 --這個可以查詢到資料

一個事務獲取了共用鎖,在其他查詢中也只能加共用鎖或不加鎖。

begin;

select * from actor where id = 1 lock in share mode

select * from actor where id = 1; 
select * from actor where id = 1 lock in share mode;
-- 可以查詢到資料

select * from actor where id = 1 for update;
-- 查詢不到資料 ,因為排他鎖與共用鎖不能存在同一資料上。

驗證下上面說的mysql InnoDb引擎中update,delete,insert語句自動加排他鎖的問題,

begin;

update actor set name = 'aa' where id = 1;

select * from actor where id = 1 lock in share mode;
 -- 此時共用查詢處於阻塞,等待排它鎖的釋放,但是用普通查詢能查到資料,因為沒用上鎖機制不與排他鎖互斥,但查到的資料是修改資料之前的老資料。

select * from actor where id = 1; -- 可查到資料

然後我們提交資料,釋放排他鎖看下修改後的資料,此時可用排他查,共用查和普通查詢, 因為事務提交後該行資料釋放排他鎖,下面就只顯示普通查詢。

二、for update

select … for update 語句是我們經常使用手工加鎖語句。會對資料庫中的表或某些行資料進行鎖表,在mysql中,如果查詢條件帶有主鍵,會鎖行資料,如果沒有,會鎖表。

  1. FOR UPDATE僅適用於InnoDB,且必須在事務處理模組(BEGIN/COMMIT)中才能生效。
  2. 要測試鎖定的狀況,可以利用MySQL的Command Mode(命令模式) ,開兩個視窗來做測試。
  3. Myisam 只支援表級鎖,InnerDB支援行級鎖 新增了(行級鎖/表級鎖)鎖的資料不能被其它事務再鎖定,也不被其它事務修改。是表級鎖時,不管是否查詢到記錄,都會鎖定表。

什麼時候需要使用for update?
藉助for update語句,我們可以在應用程式的層面手工實現資料加鎖保護操作。就是那些需要業務層面資料獨佔時,可以考慮使用for update。

場景上,比如火車票訂票,在螢幕上顯示有票,而真正進行出票時,需要重新確定一下這個資料沒有被其他使用者端修改。所以,在這個確認過程中,可以使用for update。

for update 悲觀鎖
悲觀鎖:總是假設最壞的情況,每次去拿資料的時候都認為別人會修改,所以每次在拿資料的時候都會上鎖,這樣別人想拿這個資料就會阻塞直到它解鎖。傳統的關係型資料庫裡邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。就像for update,再比如Java裡面的同步原語synchronized關鍵字的實現也是悲觀鎖。

樂觀鎖:顧名思義,就是很樂觀,每次去拿資料的時候都認為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個資料,可以使用版本號等機制。樂觀鎖適用於多讀的應用型別,這樣可以提高吞吐量,像資料庫提供的類似於write_condition機制,其實都是提供的樂觀鎖。