程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> MYSQL數據庫 >> MySQL綜合教程 >> MySQLInnoDB存儲引擎之鎖

MySQLInnoDB存儲引擎之鎖

編輯:MySQL綜合教程

MySQLInnoDB存儲引擎之鎖


概念:
鎖是用來管理對共享文件的並發訪問。innodb會在行級別上對數據庫上鎖。不過innodb存儲引擎會在數據庫內部其他多個地方使用鎖,從而允許對不同資源提供並發訪問。例如操作緩沖池中的LRU列表,刪除,添加,移動LRU列表中的元素,為了保證一致性,必須有鎖的介入。MyISAM引擎是表鎖,而InnoDB提供一致性的非鎖定讀、行級鎖,且行級鎖沒有相關額外的開銷。

table-level locking(表級鎖)
整個表被客戶鎖定。根據鎖定的類型,其他客戶不能向表中插入記錄,甚至從中讀數據也受到限制MyISAM、MEMORY默認鎖級別,個別時候,InnoDB也會升級為表級鎖
row-level locking(行級鎖)
只有線程當前使用的行被鎖定,其他行對於其他線程都是可用的InnoDB默認行級鎖。是基於索引數據結構來實現的,而不是像ORACLE的鎖,是基於block的。InnoDB也會升級為表級鎖,全表/全索引更新,請求autoinc鎖等
page-level locking(頁級鎖)
鎖定表中某些行集合(稱做頁),被鎖定的行只對鎖定最初的線程是可行。如果另外一個線程想要向這些行寫數據,它必須等到鎖被釋放。不過其他頁的行仍然可以使用BDB默認頁級鎖
lock與latch
latch稱為闩鎖(輕量級的鎖),因為其要求鎖定的時間必須非常短。若持續的時間長,則應用的性能會非常差。在InnoDB存儲引擎中,又可以分為mutex(互斥量)和rwlock(讀寫鎖)。其目的是用來保證並發線程操作臨界資源的正確性,並且通常沒有死鎖檢測的機制。latch可以通過命令show engine innodb mutex來進行查看。如圖:\
由上圖可以看出列Type顯示的總是InnoDB,列Name顯示latch的信息以及所在源碼的行數,列Status中顯示的os_waits表示操作系統等待的次數。
lock的對象是事務,用來鎖定的是數據庫中的對象,如表、頁、行。並且一般lock的對象僅在事務commit或者rollback後釋放(不同事務隔離級別釋放的時間可能不一樣)。有死鎖機制。二則的區別如下:
\
特點:
InnoDB是通過對索引上的索引項加鎖來實現行鎖。這種特點也就意味著,只有通過索引條件檢索數據,InnoDB才使用行級鎖,否則,InnoDB將使用表鎖。
鎖的類型:
有兩種標准的行級鎖:
共享鎖(S lock):允許一個事務去讀一行,阻止其他事務獲得相同數據集的排他鎖.SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE
排它鎖(X lock):允許獲得排他鎖的事務更新數據,阻止其他事務取得相同數據集的共享讀鎖和排他鎖.SELECT * FROM table_name WHERE ... FOR UPDATE
InnoDB存儲引擎支持意向鎖且設計比較簡練,分為兩種內部使用的意向鎖(Intention Locks),這兩種意向鎖都是表鎖。(意向鎖是InnoDB自動加的)
意向共享鎖(IS):事務打算給數據行加行共享鎖,事務在給一個數據行加共享鎖前必須先取得該表的IS鎖.
意向獨占鎖(IX):事務打算給數據行加行排他鎖,事務在給一個數據行加排他鎖前必須先取得該表的IX鎖.
表級意向鎖與行級鎖的兼容情況如下圖:
\
鎖的查看
在InnoDB1.0版本之前只能通過show engine innodb status(transactions行中查看) 或者 show full processlist來查看當前庫中鎖的請求。但是在這之後在information_schema架構下新增innodb_trx、innodb_locks和innodb_lock_waits三張表記錄當前庫中鎖的情況。
三個表的字段說明如下圖\\vcq9wLS2wcihtbHHsNa00NDKsbzkyv2+3b/i1tDQ0LXEyv2+3aGjyOe5+7bByKG1xNDQ1f3U2ta00NBkZWxldGW78tXfdXBkYXRlstnX96Os1eLKsbbByKGy2df3sru74dLytMvIpbXItP3Q0MnPy/i1xMrNt8Who8/gt7S12KOsSW5ub0RCtOa0otL9x+a74ciltsHIodDQtcTSu7j2v+zV1cr9vt0otbHHsNDQyv2+3bXEwPrKt7Dmsb4poaO/7NXVyv2+3crH1ri4w9DQtcTWrsewsOaxvrXEyv2+3aOsuMPKtc/WysfNqLn9dW5kb7bOwLTN6rPJoaO2+HVuZG/Tw8C01NrKws7xu9i59sr9vt2jrNLytMu/7NXVyv2+3bG+ye3Kx8O709C27s3iv6rP+qGjtvjH0qOstsHIob/s1dXK/b7dyseyu9Do0qrJz8v4tcSho9K71sLQ1LfHy/i2qLbBysdJbm5vREK05rSi0v3H5rXExKzIz7bByKG3vcq9KNTatsHIobK7u+HVvNPDus21yLT9se3Jz7XEy/gpoaO1q8rH1Nqyu82sysLO8bj0wOu8trHwz8KjrLbByKG1xLe9yr2yu82so6yyorK7ysfU2sO/uPbKws7xuPTA67y2sfDPwra8yseyydPDt8fL+LaotcTSu9bC0NS2waGjvLTKuba8ysfKudPDt8fL+LaotcTSu9bC0NS2waOstavKx7bU09q/7NXVyv2+3bXEtqjS5SYjMjY2ODQ7yr3Ssrj3srvP4M2soaPU2srCzvG49MDrvLax8FJFQUQKIENPTU1JVFRFRChSQym6zVJFUEVBVEFCTEUgUkVBRChSUixJbm5vREK05rSi0v3H5rXExKzIz8rCzvG49MDrvLax8CnPwqOsSW5ub0RCtOa0otL9x+bKudPDt8fL+LaotcTSu9bC0NS2waGjyLu2+KOsttTT2r/s1dXK/b7dtcS2qNLlyKWyu8/gzayho9TaUkPKws7xuPTA67y2sfDPwqOsttTT2r/s1dXK/b7do6y3x9K71sLQ1LbB19zKx7bByKGxu8v4tqjQ0LXE1+7QwtK7t92/7NXVyv2+3aGjtvjU2lJSysLO8bj0wOu94rDzz8KjrLbU09q/7NXVyv2+3aOst8fSu9bC0NS2wdfcyse2wcihysLO8b+qyrzKsbXE0NDK/b7dsOaxvqGjPGJyPgogICAg0rvWwtDUy/i2qLbBPGJyPgogICAgICAgINPQyc/OxNaqtcCjrMSsyM+1xMrCzvG49MDrvLax8ChSUinEo8q9z8KjrElubm9EQrTmtKLS/cfmtcRzZWxlY3Sy2df3yrnTw9K71sLQ1LfHy/i2qLbBoaO1q8rH1NrEs9Cpx+m/9s/Co6zTw7un0OjSqs/Uyr212LbUyv2+3b/itsGy2df3vNPL+NLUsaPWpMr9vt3C37yttcTSu9bC0NSho0lubm9EQrTmtKLS/cfmttTT2nNlbGVjdNPvvuTWp7PWwb3W1tK71sLQ1LXEy/i2qLbBstnX9zo8YnI+CiAgICAgICAgICAgIHNlbGVjdCAuLi4gZm9yIHVwZGF0ZaO6ttS2wcihtcTQ0LzHwry801jL+KOsxuTL+8rCzu+yu8TcttS4w9DQvNPIzrrOy/ihozxicj4KICAgICAgICAgICAgc2VsZWN0IC4uLiBsb2NrIGluIHNoYXJlIG1vZGWjurbUtsHIobXE0NC8x8K8vNNTy/ijrMbky/vKws7vv8nS1LbUuMPQ0LzTU8v4o6y1q8rHyOe5+7zTWMv4o6zU8rvhsbvX6Mj7oaM8YnI+CiAgICDX1NT2s6TT68v4PGJyPgogICAgICAgINTaSW5ub0RCtOa0otL9x+a1xMTatOa94bm51tCjrLbUw7+49rqs09DX1NT2s6QmIzIwNTQwO7XEse22vNPQ0ru49tfU1PazpLzGyv3G9yhhdXRvLWluY3JlbWVudCBjb3VudGVyKaGjtbG21Lqs09DX1NT2s6S1xLzGyv3G97XEse29+NDQsuXI67LZ1/fKx6Os1eK49rzGyv3G97vhsbuz9cq8u6+jrNa00NDI58/CtcTT777kwLS1w7W9vMbK/cb3tcQmIzIwNTQwOzpzZWxlY3QgbWF4KGF1dG9faW5jX2NvbCkgZnJvbSB0IGZvciB1cGRhdGWho7LlyOuy2df3u+HSwL7d1eK49tfU1PazpLXEvMbK/cb3JiMyMDU0MDu80zG4s9Po19TU9rOkwdCho9XiuPbKtc/Wt73KvbPGzqpBVVRPLUlOQyBMb2NraW5no6zV4srH0rvW1szYyuK1xLHty/i7+tbGo6zOqsHLzOG437LlyOu1xNDUxNyjrMv4srvKx9Ta0ru49srCzvHN6rPJ1q6687LFys23xaOstvjKx9TazeqzybbU19TU9rOkJiMyMDU0MDuy5cjrtcRTUUzT777kuvO74cGivLTKzbfFoaNBVVRPLUlOQwogTG9ja2luZ9Ta0ru2qLPMtsjJz8zhuN/By7Kit6Ky5cjrtcTQp8LKo6y1q8rHu7m05tTa0rvQqdDUxNzJz7XEzsrM4qGjytfPyKOsttTT2tPQ19TU9rOkJiMyMDU0MDu1xMHQtcSyoreisuXI69DUxNy9z7Luo6zKws7xsdjQ67XItP3HsNK7uPay5cjrtcTN6rPJKLK708O1yLT9ysLO8bXEzeqzySmho8bktM6jrLbU09ppbnNlcnQgLi4uIHNlbGVjdLXEtPPK/b7dwb+1xLLlyOu74dOwz+yy5cjrtcTQ1MTco6zS8s6qwe3Su7j2ysLO8dbQtcSy5cjru+Gxu9foyPuho7TTTXlTUUw1LjEuMjKw5rG+v6rKvKOsSW5ub0RCtOa0otL9x+bM4bmpwcvSu9bWx+HBv7y2u6Wz4sG/tcTX1NT2s6TKtc/Wu/rWxqOs1eLW1rv61sa087TzzOG438HL19TU9rOkJiMyMDU0MDuy5cjrtcTQ1MTcoaPNqLn9ss7K/Wlubm9kYl9hdXRvaW5jX2xvY2tfbW9kZcC0v9jWxtfU1PazpLXExKPKvSjErMjPzqoxKaGj19TU9rOktcSy5cjrvfjQ0LfWwODI5828OjxpbWcgc3JjPQ=="http://www.2cto.com/uploadfile/Collfiles/20141220/20141220092504215.jpg" alt="\">
innodb_autoinc_lock_mode的參數值及其對自增長的影響如下圖:\
MyISAM存儲引擎是表鎖,自增長不用考慮並發插入的問題。需要注意的是:在InnoDB存儲引擎中,自增長值的列必須是索引,同時必須是索引的第一個列,如果不是第一個列,MySQL是會拋出異常的。異常如圖\
外鍵與鎖
外鍵主要用於完整性的約束檢查。在InnoDB存儲引擎中,對於一個外鍵列,如果沒有顯式地對這個列加索引,InnoDB存儲引擎會自動對其加一個索引,避免表鎖。對於外鍵值的插入或者更新,首先需要查詢父表中的記錄,對於父表的select操作,不是使用的一致性非鎖定讀的方式,因為這樣會發生數據不一致的問題,所以這時使用的是select ... lock in share mode方式,即主動給父表加一個S鎖。
鎖的問題
dirty read 髒讀
髒讀就是讀取到髒數據(未提交的數據)。一個事務(A)讀取到另一個事務(B)中修改後但尚未提交的數據,並在這個數據的基礎上操作。這時,如果B事務回滾,那麼A事務讀到的數據是無效的。不符合一致性。如圖\
首先事務的隔離級別有默認的RR改為RU,由上述例子可以看出會話B中兩次select操作取得了不同的結果,並且這2條記錄是會話A中並未提交的數據,這就產生了髒讀。由此可以得出結論:髒讀發生的條件是事務的隔離級別為RU。
unrepeatable read 不可重復讀
事務(A)讀取到了另一個事務(B)已經提交的更改數據,不符合隔離性。不可重復讀和髒讀的區別是:髒讀是讀到未提交的數據,而不可重復讀則讀到的是已經提交的數據。首先將事務隔離級別調整為RC,然後操作下邊的例子:\
phantom read 幻讀
事務(A)讀取到了另一個事務(B)提交的新增數據,不符合隔離性。
鎖的范圍(鎖的算法):
1.Record Lock :單個記錄上的鎖,總是會去鎖住索引記錄,如果InnoDB存儲引擎表在建立的時候沒有設置任何一個索引,那麼這時InnoDB存儲引擎會使用隱式的主鍵來進行鎖定。
2.Gap Lock:間隙鎖,鎖定一個范圍,但不包含記錄本身。
3.Next-key Lock: 鎖定一個范圍和本身 Record Lock + Gap Lock,防止幻讀。
主鍵索引和唯一輔助索引 = record lock
非唯一輔助索引 = next-key lock
阻塞
不同鎖之間的兼容性關系,在有些時刻一個事務中的鎖需要等待另外一個事務中的鎖釋放它所占用的資源,這就是阻塞。阻塞並不是一件壞事,其是為了確保事務可以並發且正常地運行。在InnoDB存儲引擎中,參數innodb_lock_wait_timeout用來動態的控制等待的時間(默認50秒),innodb_rollback_on_timeout用來靜態的設定釋放在等待超時時對進行的事務進行回滾操作(默認OFF,代表不回滾)。
死鎖

死鎖是指兩個或者兩個以上的事務在執行過程中,因爭奪資源而造成的一種相互等待的現象。解決死鎖最簡單的一種方式是超時,即當兩個事務相互等待是,當一個等待時間超過設置的某一閥值時,其中一個事務進行回滾,另外一個等待的事務就能繼續進行。在InnoDB存儲引擎中,參數innodb_lock_wait_timeout用來設置超時時間。但若超時的事務所占權重比較大,如果事務操作更新了很多行,占用了較多的undo log,這時采用FIFO的方式就不合適啦,因為回滾這個事務的時間相對於另一個事務所占用的時間可能會很多。因此,除了超時機制,當前數據庫都普遍采用wait-for graph(等待圖)的方式來進行死鎖檢測。要求數據庫報錯以下兩種信息:a.鎖的信息鏈表;b.事務等待鏈表。通過上述鏈表可以構造一張圖,而在這個圖中若存在回路,就代表存在死鎖。在wait-for graph中,事務為圖中的節點。如圖:

如圖可以發現存在回路(1,2),因此存在死鎖,這時InnoDB存儲引擎選擇回滾undo量最小的事務。wait-for graph的死鎖檢測通常采用深度優先的算法實現。
注意:
1.S X IS IX,表示的是,本鎖和其他鎖共存的方式,是互斥還是兼容
2.RECORD LOCK、GAP LOCK、NEXT-KEY LOCK,表示的是,這些鎖要加載的范圍,是行記錄本身,還是行記錄+間隙,甚至更大的范圍
重要的結論:
1、任何輔助索引上的鎖,或者非索引列上的鎖,最終都要回溯到主鍵上,在主鍵上也要加一把鎖
2、任何葉子節點上的S或X鎖之前,都會在根節點加一個IS或IX鎖,也就是表級別的IS、IX鎖
3、主鍵索引上的鎖,都是record lock
4、唯一索引輔助索引上的鎖,也都是record lock
5、非唯一索引輔助索引上的鎖,則是next-key lock
6、不會有單獨的gap lock出現,只會伴隨著record lock出現,依附於它

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved