數據的鎖主要用來保證數據的一致性,數據庫的鎖從鎖定的粒度上能夠分爲表級鎖,行級鎖和頁級鎖。mysql
MySQL的鎖機制比較簡單,其最顯著的特色是不一樣的存儲引擎支持不一樣的鎖機制,好比MyISAM和MEMORY存儲引擎採用的是表級鎖(table-level locking);BDB存儲引擎採用的是頁面鎖(page-level locking),但也支持表級鎖;InnoDB存儲引擎既支持行級鎖(row-level locking),也支持表級鎖,但默認狀況下采用行級鎖。sql
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存儲引擎只支持表鎖,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
能夠設置改變讀鎖和寫鎖的優先級:
在自動加鎖的狀況下,MyISAM老是一次得到SQL語句所須要的所有鎖,這也正是MyISAM表不會出現死鎖(Deadlock Free)的緣由。
MyISAM存儲引擎支持併發插入,以減小給定表的讀和寫操做之間的爭用:
若是MyISAM表在數據文件中間沒有空閒塊,則行始終插入數據文件的末尾。 在這種狀況下,你能夠自由混合併發使用MyISAM表的INSERT和SELECT語句而不須要加鎖——你能夠在其餘線程進行讀操做的時候,同時將行插入到MyISAM表中。 文件中間的空閒塊多是從表格中間刪除或更新的行而產生的。 若是文件中間有空閒快,則併發插入會被禁用,可是當全部空閒塊都填充有新數據時,它又會自動從新啓用。 要控制此行爲,可使用MySQL的concurrent_insert系統變量。
若是你使用LOCK TABLES顯式獲取表鎖,則能夠請求READ LOCAL鎖而不是READ鎖,以便在鎖定表時,其餘會話可使用併發插入。
能夠經過檢查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)