MySQL中的表級鎖

數據的鎖主要用來保證數據的一致性,數據庫的鎖從鎖定的粒度上能夠分爲表級鎖,行級鎖和頁級鎖。mysql

MySQL的鎖機制比較簡單,其最顯著的特色是不一樣的存儲引擎支持不一樣的鎖機制,好比MyISAM和MEMORY存儲引擎採用的是表級鎖(table-level locking);BDB存儲引擎採用的是頁面鎖(page-level locking),但也支持表級鎖;InnoDB存儲引擎既支持行級鎖(row-level locking),也支持表級鎖,但默認狀況下采用行級鎖。sql

  • 表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖衝突的機率最高,併發度最低。
  • 行級鎖:開銷大,加鎖慢,會出現死鎖,鎖定粒度最小,發生鎖衝突的機率最低,併發度也是最高
  • 頁面鎖:開銷和加鎖時間結餘表鎖和行鎖之間;會出現死鎖;鎖定粒度介於表鎖和行鎖之間,併發多通常。

 查看你的MySQL數據支持哪些存儲引擎

mysql> show engines;
mysql> show engines;
+------------+---------+------------------------------------------------------------+--------------+------+------------+
| Engine     | Support | Comment                                                    | Transactions | XA   | Savepoints |
+------------+---------+------------------------------------------------------------+--------------+------+------------+
| MRG_MYISAM | YES     | Collection of identical MyISAM tables                      | NO           | NO   | NO         |
| CSV        | YES     | CSV storage engine                                         | NO           | NO   | NO         |
| MyISAM     | DEFAULT | Default engine as of MySQL 3.23 with great performance     | NO           | NO   | NO         |
| InnoDB     | YES     | Supports transactions, row-level locking, and foreign keys | YES          | YES  | YES        |
| MEMORY     | YES     | Hash based, stored in memory, useful for temporary tables  | NO           | NO   | NO         |
+------------+---------+------------------------------------------------------------+--------------+------+------------+
5 rows in set (0.00 sec)

MyISAM表鎖

MyISAM存儲引擎只支持表鎖,MySQL的表級鎖有兩種模式:表共享讀鎖(Table Read Lock)和表獨佔寫鎖(Table Write Lock)。數據庫

對於讀操做,能夠增長讀鎖,一旦數據表被加上讀鎖,其餘請求能夠對該表再次增長讀鎖,可是不能增長寫鎖。(當一個請求在讀數據時,其餘請求也能夠讀,可是不能寫,由於一旦另外一個線程寫了數據,就會致使讀取到的數據不是最新的了,這就是不可重複讀現象)併發

對於寫操做,能夠增長寫鎖,一旦數據表被加上寫鎖,其餘請求沒法對該表增長讀鎖和寫鎖。(當一個請求在寫數據時,其餘請求不能執行任何操做,由於在當前事務提交以前,其餘請求沒法看到本次修改的內容。這有可能產生讀髒數據,不可重複讀和幻讀)ide

讀鎖和寫鎖都是阻塞鎖。spa

若是t1對數據表增長了寫鎖,這時t2請求對數據表增長寫鎖,這時候t2並不會直接返回,而是會一直處於阻塞狀態,知道t1釋放了對錶的鎖,這時t2遍有可能加鎖成功,獲取到結果。線程

表級鎖的加鎖/解鎖方式

MyISAM在執行查詢語句(SELECT)前,會自動給設計的全部表加讀鎖,在執行更新操做(Update,Delete,Insert等)前,會自動給所涉及的表加寫鎖,這個過程並不須要用戶干預,所以,用戶通常不須要直接用LOCK TABLE命令給MyISAM表顯式加鎖。設計

MyISAM表的讀操做和寫操做之間,以及寫操做之間是串行的。當一個線程得到對一個表的寫鎖後,只有持有所的線程能夠對錶進行更新操做。其餘線程的讀,寫操做都會等待,知道鎖被釋放爲止。code

默認狀況下,寫鎖比讀鎖具備更高的優先級:當一個鎖釋放時,這個鎖會優先給寫鎖隊列中等候的獲取鎖清秋,而後再給讀鎖隊列中等候的獲取鎖請求。這也正是MyISAM表不太適合有大量更新操做和查詢操做應用的緣由,由於,大量的更新操做會形成查詢操做很難得到讀鎖,從而可能永遠阻塞。同時,一些須要長時間運行的查詢操做,也會使寫線程「餓死」,應用中應儘可能避免出現長時間運行的查詢操做(在可能的狀況下能夠經過使用中間表等措施對SQL語句作必定的分解,使每一步都能在較短的時間完成,從而減小鎖衝突。若是複雜查詢不可避免,應儘可能安排在數據庫空閒時段進行,好比一些按期統計能夠安排在夜間執行)。orm

能夠設置改變讀鎖和寫鎖的優先級:

  • 經過指定啓動參數low-priority-updates,使MyISAM引擎默認給予讀請求以優先的權利。
  • 經過執行命令SET LOW_PRIORITY_UPDATES=1,使該鏈接發出的更新請求優先級下降。
  • 經過指定INSERT,UPDATE,DELETE語句的LOW_PRIORITY屬性,下降該語句的優先級
  • 給系統參數max_write_lock_count設置一個合適的值,當一個表的讀鎖達到這個值後MySQL就暫時將寫請求的優先級下降,給讀今次那個必定得到鎖的機會。

在自動加鎖的狀況下,MyISAM老是一次得到SQL語句所須要的所有鎖,這也正是MyISAM表不會出現死鎖(Deadlock Free)的緣由。

MyISAM存儲引擎支持併發插入,以減小給定表的讀和寫操做之間的爭用:

若是MyISAM表在數據文件中間沒有空閒塊,則行始終插入數據文件的末尾。 在這種狀況下,你能夠自由混合併發使用MyISAM表的INSERT和SELECT語句而不須要加鎖——你能夠在其餘線程進行讀操做的時候,同時將行插入到MyISAM表中。 文件中間的空閒塊多是從表格中間刪除或更新的行而產生的。 若是文件中間有空閒快,則併發插入會被禁用,可是當全部空閒塊都填充有新數據時,它又會自動從新啓用。 要控制此行爲,可使用MySQL的concurrent_insert系統變量。

若是你使用LOCK TABLES顯式獲取表鎖,則能夠請求READ LOCAL鎖而不是READ鎖,以便在鎖定表時,其餘會話可使用併發插入。

  • 當concurrent_insert設置爲0時,不容許併發插入。
  • 當concurrent_insert設置爲1時,若是MyISAM表中沒有空洞(即表的中間沒有被刪除的行),MyISAM容許在一個線程讀表的同時,另外一個線程從表尾插入記錄。這也是MySQL的默認設置。
  • 當concurrent_insert設置爲2時,不管MyISAM表中有沒有空洞,都容許在表尾併發插入記錄。

查詢表級鎖爭用狀況

能夠經過檢查table_locks_waited和table_locks_immediate狀態變量來分析系統上的表鎖的爭奪,若是table_locks_waited的值比較高,則說明存在着較嚴重的表級鎖爭用狀況:

mysql> SHOW STATUS LIKE 'Table%';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| Table_locks_immediate | 48595 |
| Table_locks_waited    | 44    |
+-----------------------+-------+
2 rows in set (0.00 sec)
相關文章
相關標籤/搜索