鎖是計算機協調多個程序或執行緒併發訪問某一資源的機制,在資料庫中,除傳統的計算資源(如cpu、ram、i/o等)的爭用以外,資料也是一種供許多使用者共享的資源。如何保證資料併發訪問的一致性、有效性是所有資料庫必須解決的乙個問題,鎖衝突也是影響資料庫併發訪問的乙個重要因素。
相比其他資料庫而言,mysql的鎖機制比較簡單,其最顯著的特點是不同的儲存引擎支援不同的鎖機制。比如,myisam和memory儲存引擎採用的是表級鎖(table-level locking);bdb儲存引擎採用的是頁面鎖(page-level locking),但也支援表級鎖;innodb儲存引擎既支援行級鎖(row-level locking),也支援表級鎖,但預設情況下是採用行級鎖。mysql這3種鎖的特性大致歸納如下
myisam儲存引擎只支援表鎖,這也是mysql開始幾個版本中唯一支援的鎖型別。隨著應用跟對事物完整性和併發性要求的不斷提高,mysql才開始開發基於事務的儲存引擎,後來慢慢出現了支援頁鎖的bdb儲存引擎和支援行鎖的innodb儲存引擎。但是myisam的表鎖依然是使用最為廣泛的鎖型別。
查詢表級鎖的爭用情況:可以通過檢查table_locks_waited和table_locks_immediate狀態變數來分析系統上的表鎖定爭奪:
mysql> show status like 'table%';+----------------------------+-------+
| variable_name | value |
+----------------------------+-------+
| table_locks_immediate | 118 |
| table_locks_waited | 0 |
| table_open_cache_hits | 5 |
| table_open_cache_misses | 3 |
| table_open_cache_overflows | 0 |
+----------------------------+-------+
5 rows in set (0.00 sec)
如果table_locks_waited的值比較高,則說明存在著較嚴重的表級鎖爭用情況。
mysql表級鎖的鎖模式
mysql的表級鎖有兩種模式:表共享讀鎖(table read lock)和表獨佔寫鎖(table write lock)。鎖模式的相容性如下表所示。當前模式\是否相容\請求鎖模式
none
讀鎖寫鎖讀鎖是
是否寫鎖是
否否
可見,對myisam表的讀操作,不會阻塞其他使用者對同一表的讀請求,但會阻塞對同一表的寫請求;對myisam表的寫操作,則會阻塞其他使用者對同一表的度和寫操作;myisam表的讀寫操作之間,以及寫操作之間是序列的。
如何加表鎖
myisam在執行查詢語句(select)前,會自動給涉及的所有表加讀鎖,在執行更新操作(update、delete、insert等)前,會自動給涉及的表加寫鎖,這個過程並不需要使用者干預,因此,使用者一般不需要直接用lock table命令給myisam表顯式加鎖。給myisam表顯式加鎖,一般是為了在一定程度模擬事務操作,實現對某一時間點多個表的一致性讀取。例如,有個訂單表orders,其中記錄有個訂單的總金額total,同時還有乙個訂單明細表order_detail,其中記錄有個訂單每一產品的金額小計subtotal,假設需要查詢這兩個表的額金額合計是否相符,可能就需要執行如下兩條sql語句:
select sum(total) from orders;select sum(subtotal) from order_detail;
這是,如果不先給兩個表加鎖,就可能產生錯誤的結果,因為地一條語句執行過程中,order_detail表可能已經發生了改變,因此,正確的方法應該是:
lock tables orders read local, order_detail read local;select sum(total) from orders;
select sum(subtotal) from order_detail;
unlock tables;
併發插入(concurrent inserts)
前面提到的myisam表的讀和寫是序列的,但這是就總體而言的,在一定條件下,myisam表也支援查詢和插入操作的併發進行。myisam儲存引擎有乙個系統變數concurrent_insert,專門用以控制其併發插入的行為,其值分別可以為0、1或2.
myisam的鎖排程
由於myisam儲存引擎的讀鎖和寫鎖是互斥的,讀寫操作是序列的。那麼乙個程序該請求某個myisam表的讀鎖,同時另乙個程序也請求同一表的寫鎖,mysql如何處理呢?答案是寫程序先獲得鎖。不僅如此,即使讀請求先到鎖等待佇列,寫請求後到,寫鎖也會插到讀鎖之前!這是因為mysql認為寫請求一般比讀請求要重要。這也正是myisam表不大適合於有大量更新操作和查詢操作應用的原因,因為,大量的更新操作會造成查詢操作很難獲得讀鎖,從而可能永遠阻塞。這種情況有可能就會變得非常糟糕!幸好可以通過一些設定來調節myisam的排程行為。雖然以上3種方法都是要麼更新優先,要麼查詢優先的方法,但還是可以用其來解決查詢相對重要的應用(如使用者登入系統)中讀鎖等待嚴重的問題。
另外,mysql也提供了一種折中的方法來調節讀寫衝突,即給系統引數max_write_lock_count設定乙個合適的值,當乙個表的讀鎖達到這個之後,mysql就暫時將寫請求的優先順序降低,給讀程序一定獲得鎖的機會。
小結
以上說明了寫優先排程機制帶來的問題和解決辦法,這裡還要強調一點:一些需要長時間執行的查詢操作,也會使寫程序「餓死」!因此,應用中應盡量避免出現長時間執行的查詢操作,不要總想用一條select語句來解決問題,因為這種看似巧妙的sql語句,往往比較複雜,執行時間較長,在可能的情況下可以通過使用中間表等措施對sql語句做一定的「分解」,是每一步查詢都能在較短時間完成,從而減少鎖衝突。如果複雜查詢不可避免,應盡量安排在資料庫空閒時段執行,比如一些定期統計可以安排在夜間執行。
MySQL鎖概述 MyISAM 表鎖
相對其他資料庫而言,mysql的鎖機制比較簡單,其最顯著的特點是不同的儲存引擎支援不同的鎖機制。比如,myisam和memory儲存引擎採用的是表級鎖 table level locking bdb儲存引擎採用的是頁面鎖 page level locking 但也支援表級鎖 innodb儲存引擎既支...
mysql 讀寫鎖 表鎖myisam
讀鎖 session1 lock table book read unlock tables session1可以讀book 不可以寫book 也不可以讀寫其它表 session2可以讀book 也可以讀寫其它表 可以寫book 但阻塞的需要session1解鎖後unlock tables 寫鎖 s...
MySQL系列 MyISAM表鎖詳解
s鎖 共享鎖 又稱讀鎖,若事務t對資料物件a加上s鎖,則事務t可以讀a但不能修改a,其他事務只能再對a加s鎖,而不能加x鎖,直到t釋放a上的s鎖。這保證了其他事務可以讀a,但在t釋放a上的s鎖之前不能對a做任何修改,除非先獲取a的x鎖。x鎖 排他鎖 又稱寫鎖,若事務t對資料物件a加上x鎖,事務t可以...