mysql的鎖機制簡介

2021-07-26 03:46:06 字數 4911 閱讀 9122

簡介鎖是計算機協調多個程序或執行緒併發訪問某一資源的機制。不同的資料庫,鎖機制的原理和實現都大同小異。由於資料庫資源是供多業務模組共享的資源,如何保證資料併發訪問的一致性、有效性和訪問效率,是所有資料庫必須解決的問題。鎖衝突,是影響資料庫併發訪問效能的乙個重要因素。了解鎖機制不僅可以使我們更有效的開發利用資料庫資源,也使我們能夠更好地維護資料庫,從而提高資料庫的效能。這篇文章主要是對mysql的**鎖(表級鎖、頁級鎖和行級鎖)及其應用場景進行簡要介紹。

表級鎖: 顧名思義,鎖住整個表。加鎖後,其它程序無法對該錶進行寫操作。對應的資料庫引擎是myisam。

行級鎖: 給單獨的一行記錄加鎖,這樣其它程序還是可以對同乙個表中的其它記錄進行操作。支援行級鎖的資料庫引擎是 innodb。  

頁級鎖:對相關聯的幾行資料加鎖。支援頁級鎖的資料庫引擎是 bdb。表級鎖速度快,但衝突多;行級鎖衝突少,但速度慢。頁級鎖是一種折中的方案,一次鎖定相鄰的一組記錄。

實現原理

mysql的鎖機制比較簡單,其最顯著的特點是不同的儲存引擎支援不同的鎖機制。

例如,myisam和memory儲存引擎採用的是表級鎖(table-level-locking);bdb儲存引擎採用的是頁級鎖(page-level-locking),同時也支援表級鎖;innodb儲存引擎既支援行級鎖,也支援表級鎖,預設情況下是採用行級鎖。

和作業系統中的鎖一樣,資料庫中的鎖也可以按照能否共享,分為「排它寫」鎖和」共享讀」鎖。

對於「排它寫」鎖,mysql的表級鎖原理如下:

如果在表上沒有鎖,在它上面放乙個寫鎖;否則,把鎖定請求放在寫鎖定佇列中。

對於「共享讀"鎖,mysql使用的鎖定方法原理如下:如果在表上沒有寫鎖,把乙個讀鎖定放在它上面;否則,把鎖請求放在讀鎖定佇列中。程序訪問資料庫時,如果表上有讀鎖,則可以讀。

行級鎖和頁級鎖都可能存在死鎖。這是因為,這兩種鎖是在sql語句處理期間——而不是在事務啟動時——獲得的。 

行級鎖的優點:

·         當在許多執行緒中訪問不同的行時,會產生較少的衝突。

·         事務回滾時,只有少量資料發生更改。

·         可以長時間鎖定單一的行。

行級鎖的缺點:

·         因為粒度更小,鎖的數量更過,因此比頁級和表級鎖占用更多的記憶體。

·         在同乙個表中大量使用行級鎖時,效能上比頁級或表級鎖速度慢很多,因為會頻繁地加、解鎖。

·         如果你在大部分資料上使用group by操作或者掃瞄整個表時,比其它兩種鎖,在處理速度上會慢很多。

·         用高階別鎖定,通過支援不同的型別鎖定,你也可以很容易地調節應用程式,因為其鎖成本小於行級鎖定。

在以下情況下,表級鎖優先於頁級或行級鎖:

·         表的大部分語句用於讀取。

·         對嚴格的關鍵字進行讀取和更新,你可以更新或刪除可以用單一的讀取的關鍵字來提取的一行:

·               update tbl_name set column=value where unique_key_col=key_value;

·               delete from tbl_name where unique_key_col=key_value;

·         select 結合並行的insert語句,並且只有很少的update或delete語句。

·         在整個表上有許多掃瞄或group by操作,沒有任何寫操作。

如果想要在乙個表上做大量的 insert 和 select 操作,但是並行的插入卻不可能時,可以將記錄插入到臨時表中,然後定期將臨時表中的資料更新到實際的表裡。可以用以下命令實現:

複製****如下:

mysql> lock tables real_table write, insert_table write;

mysql> insert into real_table select * from insert_table;

mysql> truncate table insert_table;

mysql> unlock tables;

應用場景

上述三種鎖的特性可大致歸納如下:

1) 表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖衝突的概率最高,併發度最低。

2) 行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的概率最低,併發度也最高。

3) 頁面鎖:開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,併發度一般。

mysql表級鎖有兩種模式:表共享讀鎖(table read lock)和表獨佔寫鎖(table write lock)。什麼意思呢,就是說對錶進行讀操作時,它不會阻塞其他使用者對同一表的讀請求,但會阻塞 對同一表的寫操作;而對錶的寫操作,則會阻塞其他使用者對同一表的讀和寫操作。

表的讀和寫是序列的,即在進行讀操作時不能進行寫操作,反之也是一樣。但在一定條件下表也支援查詢和插入的操作的併發進行,其機制是通過控制乙個系統變數(concurrent_insert)來進行的,當其值設定為0時,不允許併發插入;當其值設定為1 時,如果表中沒有空洞(即表中沒有被刪除的行),允許在乙個程序讀表的同時,另乙個程序從表尾插入記錄;當其值設定為2時,無論表中有沒有空洞,都允許在表尾併發插入記錄。

表級鎖排程是如何實現的呢,這也是乙個很關鍵的問題。例如,當乙個程序請求某個myisam表的讀鎖,同時另乙個程序也請求同一表的寫鎖,此時mysql將會如優先處理程序呢?通過研究表明,寫程序將先獲得鎖(即使讀請求先到鎖等待佇列)。但這也造成乙個很大的缺陷,即大量的寫操作會造成查詢操作很難獲得讀鎖,從而可能造成永遠阻塞。所幸我們可以通過一些設定來調節myisam的排程行為。我們可通過指定引數low-priority-updates,使myisam預設引擎給予讀請求以優先的權利,設定其值為1(set low_priority_updates=1),使優先順序降低。

有如下兩種模式的行級鎖:

1)共享鎖:允許乙個事務去讀一行,阻止其他事務獲得相同資料集的排他鎖。

( select * from table_name where ......lock in share mode)

2)排他鎖:允許獲得排他鎖的事務更新資料,阻止其他事務取得相同資料集的共享讀鎖和  排他寫鎖。(select * from table_name where.....for update)

為了允許行鎖和表鎖共存,實現多粒度鎖機制;同時還有兩種內部使用的意向鎖(都是表鎖),分別為意向共享鎖和意向排他鎖。

innodb引擎的行鎖是通過給索引項加鎖來實現的,即只有通過索引條件檢索資料,innodb才使用行級鎖,否則將使用表鎖!

另外:插入,更新效能優化的幾個重要引數

**如下:

bulk_insert_buffer_size

批量插入快取大小, 這個引數是針對myisam儲存引擎來說的.適用於在一次性插入100-1000+條記錄時, 提高效率.預設值是8m.可以針對資料量的大小,翻倍增加.

concurrent_insert

併發插入, 當表沒有空洞(刪除過記錄), 在某程序獲取讀鎖的情況下,其他程序可以在表尾部進行插入.

值可以設0不允許併發插入, 1當表沒有空洞時, 執行併發插入, 2不管是否有空洞都執行併發插入.

預設是1 針對表的刪除頻率來設定.

delay_key_write

針對myisam儲存引擎,延遲更新索引.意思是說,update記錄時,先將資料up到磁碟,但不up索引,將索引存在記憶體裡,當表關閉時,將記憶體索引,寫到磁碟. 值為 0不開啟, 1開啟. 預設開啟.

delayed_insert_limit,delayed_insert_timeout, delayed_queue_size

延遲插入, 將資料先交給記憶體佇列, 然後慢慢地插入.但是這些配置,不是所有的儲存引擎都支援, 目前來看, 常用的innodb不支援, myisam支援. 根據實際情況調大, 一般預設夠用了

舉個例子: 假設有個表單products ,裡面有id跟name二個字段,id是主鍵。

例1: (明確指定主鍵,並且有此筆資料,row lock)

複製****如下:

select * from products where id='3' forupdate;

select * from products where id='3' and type=1 for update;

例2: (明確指定主鍵,若查無此筆資料,無lock)

複製****如下:

select * from products where id='-1' forupdate;

例3: (無主鍵,table lock)

複製****如下:

select * from products where name='mouse'for update;

例4: (主鍵不明確,table lock)

複製****如下:

select * from products where id<>'3'for update;

例5: (主鍵不明確,table lock)

複製****如下:

select * from products where id like '3'for update;

注1: for update僅適用於innodb,且必須在交易區塊(begin/commit)中才能生效。

注2: 要測試鎖定的狀況,可以利用mysql的command mode ,開二個視窗來做測試。

在mysql 5.0中測試確實是這樣的

是表級鎖時,不管是否查詢到記錄,都會鎖定表

此外,如果a與b都對錶id進行查詢但查詢不到記錄,則a與b在查詢上不會進行row鎖,但a與b都會獲取排它鎖,此時a再插入一條記錄的話則會因為b已經有鎖而處於等待中,此時b再插入一條同樣的資料則會丟擲deadlock foundwhen trying to get lock; try restarting transaction然後釋放鎖,此時a就獲得了鎖而插入成功。

mysql鎖機制 mysql 鎖機制

一 概述 mysql有三種鎖的級別 頁級 表級 行級。myisam和memory儲存引擎採用的是表級鎖 table level locking bdb儲存引擎採用的是頁面鎖 page level locking 但也支援表級鎖 innodb儲存引擎既支援行級鎖 row level locking 也...

mysql鎖機制 php Mysql鎖機制

表級鎖 開銷小,加鎖快 不會出現死鎖 鎖定粒度大,發生鎖衝突的概率最高,併發度最低。行級鎖 開銷大,加鎖慢 會出現死鎖 鎖定粒度最小,發生鎖衝突的概率最低,併發度也最高。共享鎖和排它鎖 頁面鎖 開銷和加鎖時間界於表鎖和行鎖之間 會出現死鎖 鎖定粒度界於表鎖和行鎖之間,併發度一般 mysql的行級鎖有...

mysql鎖機制總結 mysql鎖機制總結

1.隔離級別 1 讀不提交 read uncommited,ru 這種隔離級別下,事務間完全不隔離,會產生髒讀,可以讀取未提交的記錄,實際情況下不會使用。2 讀提交 read commited,rc 僅能讀取到已提交的記錄,這種隔離級別下,會存在幻讀現象,所謂幻讀是指在同乙個事務中,多次執行同乙個查...