Mysql鎖原理淺談


鎖類型/引擎 行鎖 表鎖 頁鎖
MyISAM
InnoDB
BDB(被InnoDB取代)

鎖的分類

  • 表鎖:開銷小,加鎖快,不會死鎖,粒度大,沖突率高,並發低。
  • 行鎖:開銷大,加鎖慢,會死鎖,粒度小,沖突率低,並發高。
  • 頁鎖:處於表鎖和行鎖之間,會死鎖。

鎖的適用場景

  • 表鎖:更適用於查詢為主,按少量索引條件更新。
  • 行鎖:更適用於大量按索引並發更新少量不同數據,同時又有並發查詢。

MyISAM表鎖

  • 查看鎖爭用相關參數:show status like 'table%';
  • Table_locks_waited的值越高表示表鎖爭用越高。
  • MyISAM表的讀操作,會阻塞同表的其他讀請求,會阻塞同表寫請求;
  • 寫操作會阻塞同表的讀請求和寫請求。
  • 讀與寫、寫與寫之間串行,持鎖線程可對表更新,其他線程讀/寫都會等待,直到鎖釋放。

MyISAM寫阻塞讀的例子

session 1 session 2
lock table user write;
select * from user; //返回查詢結果 select * from user; //被阻塞,等待鎖被釋放
unlock tables; 獲得鎖,返回查詢結果
注:
  1. lock tables時,要一次性鎖定用到的所有表
  2. 對別名也需要鎖定,如:lock table user as a read, user as b read;

MyISAM讀阻塞寫例子

session 1 session 2
lock table user read;
可查詢:select * from user; 可查詢:select * from user;
不能查詢未鎖定的表:select * from goods; //Table 'goods' was not locked with Lock Tables 能查詢/更新未鎖定的表
當前session更新鎖定表會報錯,Read Lock 更新鎖定表會等待
Unlock tables; 獲得鎖,更新完成

MyISAM並發插入

系統變量 concurrent_insert:用於控制並發插入行為

  • 0 不允許並發插入
  • 1 表中沒有被刪除的行(即沒有空洞),則允許一個進程讀,另一個進程在表尾插入(默認設置)
  • 2 表中不論是否存在空洞,都允許在表尾並發插入

MyISAM讀寫並發

session 1 session 2
lock table user read local;
當前session無法對該表更新或插入 可以插入,但更新需要等待鎖釋放
無法訪問其他session插入的數據
unlock tables; 獲得鎖,更新完成
可以查到其他session插入的數據
注:
  • 利用並發插入可以解決應用對同一個表查詢和插入的鎖爭用;
  • 將cocurrent_insert設置為2,定期OPTIMIZE TABLE來整理空間碎片,回收刪除記錄產生的空洞。

MyISAM鎖調度

  1. 讀鎖與寫鎖互斥;
  2. 讀操作與寫操作串行;
  3. 寫進程先獲得鎖,即使讀請求先到隊列,也會被寫請求插隊,因為mysql認為寫比讀要重要(因此MyISAM不適合有大量更新/插入操作)。

調節MyISAM鎖調度行為

  • low-priority-updates,給予讀優先權利;
  • SET LOW-PRIORITY_UPDATES=1,降低更新請求優先級;
  • 指定INSERT、UPDATE、DELETE的LOW-PRIORITY屬性,降低該語句優先級。

解決讀寫沖突的方法:

  • 系統參數 max_write_lock_count 設置合理值,表的讀鎖達到設定閾值后,mysql就將寫請求優先級降低。
  • 一些需要長時間運行的讀操作,需要拆分為多條短select sql,復雜查詢放在數據庫空閑時段進行,比如夜間執行。

InnoDB與MyISAM最大區別:

  1. 支持事務;
  2. 行級鎖。

事務 - Transaction

事務操作 描述
BEGIN 或者 START TRANSACTION 開始事務
COMMIT 提交事務
ROLLBACK 回滾結束事務,撤銷進行中的所有未提交的修改
SAVEPOINT identifier 設置保存點
RELEASE SAVEPOINT identifier 事務回滾到保存點
ROLLBACK TO identifier 撤銷保存點
SET TRANSACTION = {READ UNCOMMITED,READ COMMITED,REPEATABLE READ,SERIALIZABLE} 設置事務隔離級別
SET AUTOCOMMIT = {0,1} 禁止/開啟自動提交

事務的特性

  • A - Atomicity 原子性:全執行/全不執行
  • C - Consistent 一致性:數據狀態一致
  • I - Isolation 隔離性:事務處理過程中的中間狀態對外不可見,不受外部並發操作影響
  • D - Durable 持久性:事務完成后對數據修改是永久性的
並發事務問題 描述 解決方案
更新丟失 兩個事務對同一行數據修改,先提交的被后提交的覆蓋 應用程序對要更新的數據加鎖
臟讀 A事務改一行數據,B事務讀到了A的改動“臟”數據,A回滾則B的數據有問題 數據庫事務隔離,解決讀一致性問題:1、讀之前加鎖,防止其他事務對數據修改;2、不加鎖,生成快照,多版本並發控制
不可重復讀 一個事務多次讀取同一數據發現被改變/刪除 同上
幻讀 一個事務按先前的條件查詢,發現其他事務插入了滿足條件的新數據 同上
注:

事務隔離級別越高,並發副作用越小,代價越高,因為事務隔離從某種程度上說使得事務串行化。

MySQL事務隔離級別

隔離級別/並發問題 讀一致性 臟讀 不可重復讀 幻讀
未提交讀 最低
已提交讀 語句級
可重復讀 事務級
可序列化 最高

獲取InnoDB行鎖爭用情況

  • show status like 'innodb_row_lock%';
  • 鎖爭用嚴重時,InnoDB_row_lock_waits和InnoDB_row_lock_time_avg值較大。

InnoDB行鎖類型

行鎖類型 描述
共享鎖 S 允許事務讀一行,阻止其他事務獲得排他鎖
排他鎖 X 允許事務更新數據,阻止其他事務獲得共享讀鎖和排他寫鎖
意向共享鎖 IS 事務打算給行加共享鎖,先取得表IS鎖
意向排他鎖 IX 事務打算給行加排他鎖,先取得表IX鎖
請求鎖模式是否兼容當前鎖模式 X IX S IS
X
IX
S
IS
注:
  • 含I的鎖與含I的鎖兼容;
  • 單X與任何鎖不兼容;
  • 單S與含X的鎖不兼容;
  • 若一個事務請求的鎖模式與當前的鎖兼容,InnoDB將請求的鎖授予該事務,不兼容就要等到鎖釋放;
  • 意向鎖是InnoDB自動加的,DELETE、UPDATE、INSERT,InnoDB會自動加X鎖,普通SELECT,InnoDB不加任何鎖。

手動加鎖的方法

  • 共享鎖(S):SELECT * FROM user LOCK IN SHARE MODE;
  • 排他鎖(X):SELECT * FROM user FOR UPDATE;
注:
  • SELECT * FROM ... LOCK IN SHARE MODE; //若當前事務加了讀鎖,進行更新會死鎖
  • SELECT * FROM ... FOR UPDATE; //一個事務加了寫鎖,其他事務加鎖操作需要等待
  • InnoDB行鎖是通過給索引上的索引項加鎖來實現的,只有通過索引條件檢索,才會使用行級鎖,否則會用表鎖;
  • 分析鎖沖突時,檢查SQL執行計划(利用explain),以確認是否真正走了索引,例如:SELECT * FROM user WHERE name = 123; //name字段是varchar類型且有索引,但條件中用了int型,類型能自動轉換,但會進行全表掃描。

間隙鎖(Next-key Lock)

概念描述

用范圍而非等值搜索數據,並且請求共享/排他鎖時,InnoDB會對所有符合條件的已有記錄的索引項加鎖,對鍵值在范圍內但不存在的記錄,即GAP-間隙,也會加鎖。

例如:
  • user表,id從1~100共100個,執行:
  • SET AUTOCOMMIT = 0;
  • SELECT * FROM id > 99 FOR UPDATE;
  • 會對id等於100的記錄的索引項加鎖,對id大於99的間隙加鎖。
作用:
  1. 滿足隔離級別要求,防止幻讀;
  2. 滿足恢復和復制需要(MySQL通過BINLOG錄入執行成功的INSERT、UPDATE、DELETE等更新語句)
存在的問題:

按范圍加鎖機制會阻塞符合條件范圍內的鍵值並發插入,造成鎖等待。

解決方法:

優化業務邏輯,盡量用相等條件來檢索數據。

注:
相等條件檢索一個不存在記錄加鎖時,InnoDB也會使用間隙鎖。例如:

  • 對上面的user表,執行:
  • SET AUTOCOMMIT = 0;
  • SELECT * FROM id = 101 FOR UPDATE;
  • 再在另一個 MySQL Session 中執行 INSERT INTO user (id, name, password, description)
    VALUES
    (101, 'clive', '123456', 'psw'); //查詢被阻塞,進入等待直至鎖釋放

死鎖的概念

死鎖是指多個事務在統一資源上,出現相互占用,並請求鎖定對方占用的資源,從而導致惡性循環的現象。

MyISAM和InnoDB在死鎖上的區別

  • MyISAM不會出現死鎖,因為MyISAM總是一次獲得所需要的全部鎖,要么全部滿足,要么全等待;
  • InnoDB除了單SQL事務,鎖是逐步獲得的,因此可能出現死鎖。一般InnoDB能自動檢測死鎖,並使一個較簡單的事務回退並釋放鎖,另一個事務獲得鎖,繼續完成事務。


免責聲明!

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



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