深入Mysql鎖機制(二)讀鎖和寫鎖

2021-09-02 05:44:01 字數 3796 閱讀 5678

這篇文章主要來介紹一下mysql資料庫中的表級鎖。

本文提到的讀鎖和寫鎖都是mysql資料庫的myisam引擎支援的表鎖的。而對於行級鎖的共享讀鎖和互斥寫鎖請閱讀mysql中的共享鎖排他鎖。我習慣在描述表鎖的時候按照讀寫來區分,在表述行鎖的時候按照共享和互斥來區分。其實無論是表鎖還是行鎖。共享鎖指的就是讀鎖!互斥鎖、排他鎖、獨佔鎖值得都是寫鎖。

mysql的鎖機制比較簡單,其最顯著的特點是不同的儲存引擎支援不同的鎖機制。比如,myisam和memory儲存引擎採用的是表級鎖(table-level locking);bdb 儲存引擎採用的是頁面鎖(page-level locking),但也支援表級鎖;innodb儲存引擎既支援行級鎖(row-level locking),也支援表級鎖,但預設情況下是採用行級鎖。

myisam 儲存引擎只支援表鎖,mysql 的表級鎖有兩種模式:表共享讀鎖(table read lock)和表獨佔寫鎖(table write lock)。

對於讀操作,可以增加讀鎖,一旦資料表被加上讀鎖,其他請求可以對該錶再次增加讀鎖,但是不能增加寫鎖。(當乙個請求在讀資料時,其他請求也可以讀,但是不能寫,因為一旦另外乙個執行緒寫了資料,就會導致當前執行緒讀取到的資料不是最新的了。這就是不可重複讀現象)

對於寫操作,可以增加寫鎖,一旦資料表被加上寫鎖,其他請求無法在對該錶增加讀鎖和寫鎖。(當乙個請求在寫資料時,其他請求不能執行任何操作,因為在當前事務提交之前,其他的請求無法看到本次修改的內容。這有可能產生髒讀、不可重複讀和幻讀)

讀鎖和寫鎖都是阻塞鎖。

如果t1對資料表增加了寫鎖,這是t2請求對資料表增加寫鎖,這時候t2並不會直接返回,而是會一直處於阻塞狀態,直到t1釋放了對錶的鎖,這時t2便有可能加鎖成功,獲取到結果。

myisam 在執行查詢語句(select)前,會自動給涉及的所有表加讀鎖,在執行更新操作 (updatedeleteinsert等)前,會自動給涉及的表加寫鎖,這個過程並不需要使用者干預,因此,使用者一般不需要直接用lock table命令給myisam表顯式加鎖。

如果使用者想要顯示的加鎖可以使用以下命令:

鎖定表:lock tables tbl_name ,[ tbl_name ,…] 

解鎖表:unlock tables

在用lock tables給表顯式加表鎖時,必須同時取得所有涉及到表的鎖。

在執行lock tables後,只能訪問顯式加鎖的這些表,不能訪問未加鎖的表;

如果加的是讀鎖,那麼只能執行查詢操作,而不能執行更新操作。

在自動加鎖的情況下也基本如此,myisam 總是一次獲得 sql 語句所需要的全部鎖。這也正是 myisam 表不會出現死鎖(deadlock free)的原因。

對錶test_table增加讀鎖:

lock tables test_table read

unlock test_table

對錶test_table增加寫鎖

lock tables test_table write

unlock test_table

比如如下sql語句:

select a.first_name,b.first_name, from actor a,actor b where a.first_name = b.first_name;
該sql語句中,actor表以別名的方式出現了兩次,分別是a,b,這時如果要在該sql執行之前加鎖就要使用以下sql:

lock table actor as a read,actor as b read;
上文 到過 myisam 表的讀和寫是序列的,但這是就總體而言的。在一定條件下,myisam表也支援查詢和插入操作的併發進行。 myisam儲存引擎有乙個系統變數concurrent_insert,專門用以控制其併發插入的行為,其值分別可以為0、1或2。

當concurrent_insert設定為0時,不允許併發插入。

當concurrent_insert設定為1時,如果myisam表中沒有空洞(即表的中間沒有被刪除的 行),myisam允許在乙個程序讀表的同時,另乙個程序從表尾插入記錄。這也是mysql 的預設設定。

當concurrent_insert設定為2時,無論myisam表中有沒有空洞,都允許在表尾併發插入記錄。

可以利用myisam儲存引擎的併發插入特性,來解決應用中對同一表查詢和插入的鎖爭用。

前面講過,myisam 儲存引擎的讀鎖和寫鎖是互斥的,讀寫操作是序列的。那麼,乙個程序請求某個 myisam 表的讀鎖,同時另乙個程序也請求同一表的寫鎖,mysql 如何處理呢?

答案是寫程序先獲得鎖

不僅如此,即使讀請求先到鎖等待佇列,寫請求後到,寫鎖也會插到讀鎖請求之前!這是因為 mysql 認為寫請求一般比讀請求要重要。這也正是 myisam 表不太適合於有大量更新操作和查詢操作應用的原因,因為,大量的更新操作會造成查詢操作很難獲得讀鎖,從而可能永遠阻塞。這種情況有時可能會變得非常糟糕!

幸好我們可以通過 一些設定來調節 myisam 的排程行為。

通過指定啟動引數low-priority-updates,使myisam引擎預設給予讀請求以優先的權利。

通過執行命令set lowpriorityupdates=1,使該連線發出的更新請求優先順序降低。

通過指定insert、update、delete語句的low_priority屬性,降低該語句的優先順序。

另外,mysql也 供了一種折中的辦法來調節讀寫衝突,即給系統引數max_write_lock_count設定乙個合適的值,當乙個表的讀鎖達到這個值後,mysql就暫時將寫請求的優先順序降低, 給讀程序一定獲得鎖的機會。

資料庫中的鎖從鎖定的粒度上分可以分為行級鎖、頁級鎖和表級鎖。

mysql的myisam引擎支援表級鎖。

表級鎖分為兩種:共享讀鎖、互斥寫鎖。這兩種鎖都是阻塞鎖。

可以在讀鎖上增加讀鎖,不能在讀鎖上增加寫鎖。在寫鎖上不能增加寫鎖。

預設情況下,mysql在執行查詢語句之前會加讀鎖,在執行更新語句之前會執行寫鎖。

如果想要顯示的加鎖/解鎖的花可以使用lock tablesunlock來進行。

在使用lock tables之後,在解鎖之前,不能操作未加鎖的表。

在加鎖時,如果顯示的指明是要增加讀鎖,那麼在解鎖之前,只能進行讀操作,不能執行寫操作。

如果一次sql語句要操作的表以別名的方式多次出現,那麼就要在加鎖時都指明要加鎖的表的別名。

myisam儲存引擎有乙個系統變數concurrent_insert,專門用以控制其併發插入的行為,其值分別可以為0、1或2。

由於讀鎖和寫鎖互斥,那麼在排程過程中,預設情況下,mysql會本著寫鎖優先的原則。可以通過low-priority-updates來設定。

《深入淺出mysql》

Mysql鎖機制 讀鎖

mysql 系列文章主頁 1 準備資料 1.1 建表 1.1.1 建立 employee表 drop table ifexists employee create table ifnot exists employee id intprimary keyauto increment,name var...

mysql會話鎖 Mysql鎖機制 寫鎖

1 準備資料 1.1 建表 1.1.1 建立 employee表 drop table if existsemployee create table if not existsemployee idint primary keyauto increment,namevarchar 40 dept i...

mysql 共享鎖 讀鎖 排他鎖 寫鎖

共享鎖概述 多個客戶端在同一時刻可以同時讀取同乙個資源,而互不干擾 互不阻塞.排他鎖概述 客戶端 當前程序 在寫入資料的時 會阻塞其他的讀鎖 寫鎖.從而保證同一時刻防止其他使用者讀取正在寫入的同一資源.在實際資料庫系統中,每時每刻都在發生鎖定 當某個使用者在修改某一部分資料時,mysql 會通過鎖定...