鎖對於傳統數據庫來講是很是重要的, 裏面也摻雜各類權衡, 概念類較多, 本文只針對部份內容作了講解.mysql
單獨給一行數據記錄加鎖, mysql 中 咱們經常使用的 InnoDB 引擎支持行鎖.sql
優點: 是常見關係型數據庫中鎖粒度最小的一種鎖, 可以有效的提升併發操做.數據庫
劣勢: 消耗更多資源, 用法不規範容易產生死鎖bash
顧名思義, 對當前操做的整張表加鎖,是目前 mysql 鎖粒度最大的一種併發
最多見的 myisam 引擎使用表鎖.高併發
InnoDB 引擎 sql 使用不當(如非主鍵、索引條件)會退化爲表鎖.性能
優點: 併發讀沒問題, 消耗資源少, 加減鎖速度快, 能夠避免死鎖.ui
劣勢: 大部分狀況下DML操做併發低, 頻繁對全表加鎖, 發生鎖衝突的機率很是高.spa
頁鎖是介於比表鎖和行鎖之間的一種鎖, 只是對數據頁進行鎖定線程
頁級鎖是MySQL中鎖定粒度介於行級鎖和表級鎖中間的一種鎖。表級鎖速度快,但併發低,行級併發高,但耗資源。因此取了折衷的頁級,一次鎖定數據頁中相鄰的一組記錄
mysql 中的BDB引擎支持頁級鎖
在 mysql 數據庫中, 從全局看, 共分爲這兩種鎖, 但他們的用處有很大區別.
latch 直譯過來爲「門閂(shuān)」, 相似於下圖
它在數據庫中的學名叫作 閂鎖(一種輕量級的鎖), 在 InnoDB 存儲引擎中,latch又能夠分爲 mutex(互斥量)和 rwlock(讀寫鎖), 其目的是用來保證併發線程操做臨界資源的正確性,而且一般沒有死鎖檢測的機制.
# 查看關於閂鎖的統計信息
SHOW ENGINE INNODB MUTEX ;
+--------+------------------------+---------+
| Type | Name | Status |
+--------+------------------------+---------+
| InnoDB | rwlock: log0log.cc:838 | waits=1 |
+--------+------------------------+---------+
複製代碼
lock 鎖, 是咱們打交道最多的一種, 它主要針對的是事務,用來鎖定的是數據庫中的對象,如前面提到的表鎖、頁鎖、行鎖。而且通常lock的對象僅在事務 commit 或 rollback 後進行釋放(不一樣事務隔離級別釋放的時間可能不一樣)。此外,lock,正如在大多數數據庫中同樣,是有死鎖機制的.
容許事物讀取數據
當你拿到了共享鎖, 你能夠讀取這條數據, 另外一我的一樣能夠拿到共享鎖去讀取數據(這裏咱們稱爲鎖兼容)
可是同時另外一我的也來了, 他同時想要拿排他鎖去更新此條數據,那麼他必須等待釋放共享鎖才能夠拿到排他鎖更新數據(這裏咱們稱之爲鎖不兼容)
容許事物刪除或更新一行數據
前面咱們舉例了 若是別人已經持有共享鎖了, 其餘人是不能擁有排他鎖的.
當一我的拿到此條數據的排他鎖, 不能同時再拿到排他鎖和共享鎖的(鎖不兼容).
排他鎖(X Lock)和任何鎖都不兼容.
咱們知道 當咱們頻繁 更新數據 加排他鎖 (X Lock) 的時候, 由於其鎖的不兼容性, 會嚴重影響正常的數據查詢性能.
一致性的非鎖定讀 是指 InnoDB 存儲引擎經過行多版本控制(multi versioning)的方式來讀取當前執行時間數據庫中行的數據。若是讀取的行正在執行 DELETE 或 UPDATE 操做,這時讀取操做不會所以去等待行上鎖的釋放。相反地,InnoDB 存儲引擎會去讀取行的一個快照數據
一致性非鎖定讀的快照數據實際上是讀的 undo 數據(undo是用來回滾事務中的數據), 沒有額外的鎖操做, 因此讀取速度很是的快.
一致性的非鎖定讀由於不須要等待排他鎖 (X Lock) 的釋放, 因此極大的提升了併發的性能, 在 innodb 事務隔離級別 不可重複讀(read-committed)、可重複讀(repeatable-read 默認級別) select 使用的是 一致性的非鎖定讀.
思考: 一致性的非鎖定讀 解決了什麼問題? 帶來了什麼問題?
在一些強一致的場景, 咱們是但願讓用戶讀取到的永遠是最新的數據. 這時候, 咱們須要使用 一致性鎖定讀 的場景.
下面展現了兩種基於數據庫查詢語句上X鎖和S鎖, 通常與顯示的事務組合使用.
SELECT…FOR UPDATE對讀取的行記錄加一個X鎖,其餘事務不能對已鎖定的行加上任何鎖
SELECT…LOCK IN SHARE MODE對讀取的行記錄加一個S鎖,其餘事務能夠向被鎖定的行加S鎖,可是若是加X鎖,則會被阻塞
FOR UPDATE 也是咱們常常所說的悲觀鎖, 對應的還有樂觀鎖, 樂觀鎖更可能是業務層面的實現, 這裏再也不講述.
死鎖是指兩個或兩個以上的進程在執行過程當中,因爲競爭資源或者因爲彼此通訊而形成的一種阻塞的現象,若無外力做用,它們都將沒法推動下去.
目前主要仍是靠業務邏輯來解決, 若是程序是串行, 就不會產生死鎖, 只有併發狀況下才有可能產生, 程序並行+數據庫並行(行級鎖)運行, 可能會發生死鎖.
這裏可使用此命令查看全部線程, 對應的提示直接 kill 掉便可
show processlist
複製代碼
查看目前鎖的狀況
1:查看當前的事務
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;
2:查看當前鎖定的事務
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
3:查看當前等鎖的事務
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;
複製代碼
固然你也能夠經過配置 innodb_lock_wait_timeout 屬性,來指定鎖的超時時間, 超時數據庫系統自動 kill.
不過若是出現了長時間獲取不到鎖, 數據庫會自動進行死鎖檢測, 並進行終止.
固然,保證業務中操做數據庫的執行順序, 避免交叉執行, 基本可以避免的死鎖狀況。
本文一部分參考概念 《mysql 技術內幕》一書.
更多有趣的計算機技術關注 呆呆熊一點通 :