Mysql專題八:Mysql 鎖

一、讀鎖與寫鎖

• 讀鎖:共享鎖、Shared Locks、S鎖。
• 寫鎖:排他鎖、Exclusive Locks、X鎖。
• select :不加鎖
在這裏插入圖片描述

(一)讀操作

對於普通 SELECT 語句,InnoDB 不會加任何鎖
select … lock in share mode

將查找到的數據加上一個S鎖,允許其他事務繼續獲取這些記錄的S鎖,不能獲取這些記錄的X鎖(會阻塞)

使用場景:讀出數據後,其他事務不能修改,但是自己也不一定能修改,因爲其他事務也可以使用select … lock in share mode 繼續加讀鎖。
select … for update

將查找到的數據加上一個X鎖,不允許其他事務獲取這些記錄的S鎖和X鎖。
使用場景:讀出數據後,其他事務即不能寫,也不能加讀鎖,那麼就導致只有自己可以修改數據。

(二)寫操作

• DELETE:刪除一條數據時,先對記錄加X鎖,再執行刪除操作。
• INSERT:插入一條記錄時,會先加隱式鎖來保護這條新插入的記錄在本事務提交前不被別的事務訪問到。
• UPDATE
• 如果被更新的列,修改前後沒有導致存儲空間變化,那麼會先給記錄加X鎖,再直接對記錄進行修改。
• 如果被更新的列,修改前後導致存儲空間發生了變化,那麼會先給記錄加X鎖,然後將記錄刪掉,再Insert一條新記錄。

隱式鎖:一個事務插入一條記錄後,還未提交,這條記錄會保存本次事務id,而其他事務如果想來對這個記錄加鎖時會發現事務id不對應,這時會產生X鎖,所以相當於在插入一條記錄時,隱式的給這條記錄加了一把隱式X鎖。

二、行鎖與表鎖

1、查看鎖情況的SQL:

SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX; -- 記錄當前運行的事務
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; -- 記錄當前出現的鎖
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS; -- 記錄鎖等待的對應關係

2、INNODB_TRX表字段:
• trx_id:InnoDB存儲引擎內部唯一的事物ID
• trx_status:當前事務的狀態, RUNNING, LOCK WAIT, ROLLING BACK or COMMITTING.
• trx_status:事務的開始時間
• trx_requested_lock_id:事務等待的鎖的ID(如果事務狀態不是LOCK WAIT,這個字段是NULL),詳細的鎖的信息可以連查INNODB_LOCKS表
• trx_wait_started:事務等待的開始時間
• trx_weight:事務的權重,反應一個事務修改和鎖定的行數,當發現死鎖需要回滾時,權重越小的值被回滾
• trx_mysql_thread_id:MySQL中的進程ID,與show processlist中的ID值相對應
• trx_query:事務運行的SQL語句
• trx_operation_state:事務當操作的類型 如updating or deleting,starting index read等
• trx_tables_in_use:查詢用到的表的數量
• trx_tables_locked:查詢加行鎖的表的數量
• trx_rows_locked:事務鎖住的行數(不是準確數字)
• trx_rows_modified:事務插入或者修改的行數

3、INNODB_LOCKS表:
• lock_id:鎖ID
• lock_trx_id:擁有鎖的事務 ID。可以和 INNODB_TRX 表 JOIN 得到事務的詳細信息。
• lock_mode:鎖的模式。
• lock_type:鎖的類型。RECORD 代表行級鎖,TABLE 代表表級鎖。
• lock_table:被鎖定的或者包含鎖定記錄的表的名稱。
• lock_index:當LOCK_TYPE=’RECORD’ 時,表示索引的名稱;否則爲 NULL。
• lock_space:當LOCK_TYPE=’RECORD’ 時,表示鎖定行的表空間 ID;否則爲 NULL。
• lock_page:當 LOCK_TYPE=’RECORD’ 時,表示鎖定行的頁號;否則爲 NULL。
• lock_rec:當 LOCK_TYPE=’RECORD’ 時,表示一堆頁面中鎖定行的數量,亦即被鎖定的記錄號;否則爲 NULL。
• lock_data:當 LOCK_TYPE=’RECORD’ 時,表示鎖定行的主鍵;否則爲NULL。

4、INNODB_LOCK_WAITS表:
• requesting_trx_id:申請鎖資源的事務ID
• requesting_lock_id:申請的鎖的ID
• blocking_trx_id:租塞的事務ID
• blocking_lock_id:租塞的鎖的ID

(一)行鎖

• LOCK_REC_NOT_GAP:單個行記錄上的鎖。
• LOCK_GAP:間隙鎖,鎖定一個範圍,但不包括記錄本身。GAP鎖的目的,是爲了防止同一事務的兩次當前讀,出現幻讀的情況。
• LOCK_ORDINARY:鎖定一個範圍,並且鎖定記錄本身。對於行的查詢,都是採用該方法,主要目的是解決幻讀的問題。

間隙鎖(LOCK_GAP、GAP鎖)

READ COMMITTED級別下

1、查詢使用的主鍵
session1:

總結:查詢使用的是主鍵時,只需要在主鍵值對應的那一個條數據加鎖即可。

2、查詢使用的唯一索引
在這裏插入圖片描述

總結:查詢使用的是唯一索引時,只需要對查詢值所對應的唯一索引記錄項和對應的聚集索引上的項加鎖即可。

3、查詢使用的普通索引
在這裏插入圖片描述
出現幻讀:
在這裏插入圖片描述
總結:查詢使用的是普通索引時,會對滿足條件的索引記錄都加上鎖,同時對這些索引記錄對應的聚集索引上的項也加鎖。

4、查詢使用沒有用到索引
在這裏插入圖片描述
總結:查詢的時候沒有走索引,也只會對滿足條件的記錄加鎖。

REPEATABLE READ級別下

1、查詢使用的主鍵和RC隔離級別一樣。
2、查詢使用的唯一索引和RC隔離級別一樣。
3、查詢使用的普通索引
在這裏插入圖片描述
解決幻讀問題:
在這裏插入圖片描述
總結:REPEATABLE READ級別可以解決幻讀,解決的方式就是加了GAP鎖

4、查詢使用沒有用到索引
在這裏插入圖片描述
總結:查詢的時候沒有走索引,會對錶中所有的記錄以及間隙加鎖。

(二)表鎖

1、表級別的S鎖、X鎖
在對某個表執行SELECT、INSERT、DELETE、UPDATE語句時,InnoDB存儲引擎是不會爲這個表添加表級別的S鎖或者X鎖的。

在對某個表執行ALTER TABLE、DROP TABLE這些DDL語句時,其他事務對這個表執行SELECT、INSERT、DELETE、UPDATE的語句會發生阻塞,或者,某個事務對某個表執行SELECT、INSERT、DELETE、UPDATE語句時,其他事務對這個表執行DDL語句也會發生阻塞。這個過程是通過使用的元數據鎖(英文名:Metadata Locks,簡稱MDL)來實現的,並不是使用的表級別的S鎖和X鎖。

• LOCK TABLES t1 READ:對錶t1加表級別的S鎖。
• LOCK TABLES t1 WRITE:對錶t1加表級別的X鎖。

儘量不用這兩種方式去加鎖,因爲InnoDB的優點就是行鎖,所以儘量使用行鎖,性能更高

2、IS鎖、IX鎖

• IS鎖:意向共享鎖、Intention Shared Lock。當事務準備在某條記錄上加S鎖時,需要先在表級別加一個IS鎖。

• IX鎖,意向排他鎖、Intention Exclusive Lock。當事務準備在某條記錄上加X鎖時,需要先在表級別加一個IX鎖。

IS、IX鎖是表級鎖,它們的提出僅僅爲了在之後加表級別的S鎖和X鎖時可以快速判斷表中的記錄是否被上鎖,以避免用遍歷的方式來查看錶中有沒有上鎖的記錄。

AUTO-INC鎖
• 在執行插入語句時就在表級別加一個AUTO-INC鎖,然後爲每條待插入記錄的AUTO_INCREMENT修飾的列分配遞增的值,在該語句執行結束後,再把AUTO-INC鎖釋放掉。這樣一個事務在持有AUTO-INC鎖的過程中,其他事務的插入語句都要被阻塞,可以保證一個語句中分配的遞增值是連續的。
• 採用一個輕量級的鎖,在爲插入語句生成AUTO_INCREMENT修飾的列的值時獲取一下這個輕量級鎖,然後生成本次插入語句需要用到的AUTO_INCREMENT列的值之後,就把該輕量級鎖釋放掉,並不需要等到整個插入語句執行完才釋放鎖。
系統變量innodb_autoinc_lock_mode:
• innodb_autoinc_lock_mode值爲0:採用AUTO-INC鎖。
• innodb_autoinc_lock_mode值爲2:採用輕量級鎖。
• 當innodb_autoinc_lock_mode值爲1:當插入記錄數不確定是採用AUTO-INC鎖,當插入記錄數確定時採用輕量級鎖。

(三)悲觀鎖和樂觀鎖

悲觀鎖
悲觀鎖用的就是數據庫的行鎖,認爲數據庫會發生併發衝突,直接上來就把數據鎖住,其他事務不能修改,直至提交了當前事務。
樂觀鎖
樂觀鎖其實是一種思想,認爲不會鎖定的情況下去更新數據,如果發現不對勁,纔不更新(回滾)。在數據庫中往往添加一個version字段來實現。

(四)死鎖

在這裏插入圖片描述

1、死鎖檢測
• 系統變量innodb_deadlock_detect:控制是否打開死鎖檢測,默認打開。
• 系統變量innodb_lock_wait_timeout:等待鎖的超時時間,默認50s。
• 系統變量innodb_print_all_deadlocks:將所有的死鎖日誌寫入到mysql的錯誤日誌中,默認是關閉的。檢測到死鎖時,InnoDB會在導致死鎖的事務中選擇一個權重比較小的事務來回滾,這個權重值可能是由該事務影響的行數(增加、刪除、修改)決定的。
SHOW ENGINE INNODB STATUS;看看最近死鎖的日誌

2、避免死鎖
• 以固定的順序訪問表和行
• 大事務拆小,大事務更容易產生死鎖
• 在同一個事務中,儘可能做到一次鎖定所需要的所有資源,減少死鎖概率
• 降低隔離級別
• 爲表添加合理的索引

以上均爲魯班學院學習資料,歡迎大家報班學習,真心推薦

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章