天天看點

MySQL進階 之 鎖MySQL鎖概述MyISAM表鎖(偏讀)InnoDB表鎖(偏寫)

MySQL鎖概述

相對其他資料庫而言,MySQL的鎖機制比較簡單,其最顯著的特點是不同的存儲引擎支援不同的鎖機制。比如,MyISAM和MEMORY存儲引擎采用的是表級鎖(table-level locking);BDB存儲引擎采用的是頁面鎖(page-level locking),但也支援表級鎖;InnoDB存儲引擎既支援行級鎖(row-level locking),也支援表級鎖,但預設情況下是采用行級鎖。

MySQL這3種鎖的特性可大緻歸納如下。

開銷、加鎖速度、死鎖、粒度、并發性能

l 表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖沖突的機率最高,并發度最低。

l 行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖沖突的機率最低,并發度也最高。

l 頁面鎖:開銷和加鎖時間界于表鎖和行鎖之間;會出現死鎖;鎖定粒度界于表鎖和行鎖之間,并發度一般。

僅從鎖的角度來說:表級鎖更适合于以查詢為主,隻有少量按索引條件更新資料的應用,如Web應用;而行級鎖則更适合于有大量按索引條件并發更新少量不同資料,同時又有并發查詢的應用,如一些線上事務處理(OLTP)系統。

MyISAM表鎖(偏讀)

MyISAM存儲引擎隻支援表鎖

查詢表級鎖争用情況

MySQL進階 之 鎖MySQL鎖概述MyISAM表鎖(偏讀)InnoDB表鎖(偏寫)
Table_locks_immediate:産生表級鎖定的次數,表示可以立即擷取鎖的查詢次數,每立即擷取鎖值加1

Table_locks_waited:出現表級鎖定争用而發生等待的次數(不能立即擷取鎖的次數,沒等待一次鎖值加1)。此值比較高則說明存在着較嚴重的表級鎖争用情況
           

MySQL的表級鎖有兩種模式:表共享讀鎖(Table Read Lock)和表獨占寫鎖(Table Write Lock)。鎖模式的相容性如下表:

相容性 None(請求鎖模式) 讀鎖(請求鎖模式) 寫鎖(請求鎖模式)
讀鎖(目前鎖模式)
寫鎖(目前鎖模式)

可見:

對MyISAM表的讀操作,不會阻塞其他使用者對同一表的讀請求,但會阻塞對同一表的寫請求;

對 MyISAM表的寫操作,則會阻塞其他使用者對同一表的讀和寫操作;

MyISAM表的讀操作與寫操作之間,以及寫操作之間是串行的。當一個線程獲得對一個表的寫鎖後,隻有持有鎖的線程可以對表進行更新操作。其他線程的讀、寫操作都會等待,直到鎖被釋放為止。

InnoDB表鎖(偏寫)

InnoDB行鎖是通過給索引上的索引項加鎖來實作的,InnoDB這種行鎖實作特點意味着:隻有通過索引條件檢索資料,InnoDB才使用行級鎖,否則,InnoDB将使用表鎖!

擷取InnoDB行鎖争用情況

MySQL進階 之 鎖MySQL鎖概述MyISAM表鎖(偏讀)InnoDB表鎖(偏寫)

對各狀态量的說明如下:

MySQL進階 之 鎖MySQL鎖概述MyISAM表鎖(偏讀)InnoDB表鎖(偏寫)

示例

MySQL進階 之 鎖MySQL鎖概述MyISAM表鎖(偏讀)InnoDB表鎖(偏寫)

通過非索引條件檢索資料,InnoDB使用表級鎖例子

session1 session2
MySQL進階 之 鎖MySQL鎖概述MyISAM表鎖(偏讀)InnoDB表鎖(偏寫)
MySQL進階 之 鎖MySQL鎖概述MyISAM表鎖(偏讀)InnoDB表鎖(偏寫)
MySQL進階 之 鎖MySQL鎖概述MyISAM表鎖(偏讀)InnoDB表鎖(偏寫)
-
-
MySQL進階 之 鎖MySQL鎖概述MyISAM表鎖(偏讀)InnoDB表鎖(偏寫)
// 等待挂起
MySQL進階 之 鎖MySQL鎖概述MyISAM表鎖(偏讀)InnoDB表鎖(偏寫)
-
-
MySQL進階 之 鎖MySQL鎖概述MyISAM表鎖(偏讀)InnoDB表鎖(偏寫)
// 逾時

通過索引條件檢索資料,InnoDB使用行級鎖例子

session1 session2
MySQL進階 之 鎖MySQL鎖概述MyISAM表鎖(偏讀)InnoDB表鎖(偏寫)
MySQL進階 之 鎖MySQL鎖概述MyISAM表鎖(偏讀)InnoDB表鎖(偏寫)
MySQL進階 之 鎖MySQL鎖概述MyISAM表鎖(偏讀)InnoDB表鎖(偏寫)
-
-
MySQL進階 之 鎖MySQL鎖概述MyISAM表鎖(偏讀)InnoDB表鎖(偏寫)

索引失效 行鎖變表鎖

MySQL進階 之 鎖MySQL鎖概述MyISAM表鎖(偏讀)InnoDB表鎖(偏寫)
session1 session2
MySQL進階 之 鎖MySQL鎖概述MyISAM表鎖(偏讀)InnoDB表鎖(偏寫)
-
-
MySQL進階 之 鎖MySQL鎖概述MyISAM表鎖(偏讀)InnoDB表鎖(偏寫)
// 等待挂起

間隙鎖

間隙鎖(Gap Lock):鎖加在不存在的空閑空間,可以是兩個索引記錄之間,也可能是第一個索引記錄之前或最後一個索引之後的空間。

間隙鎖是innodb中行鎖的一種,但是這種鎖鎖住的卻不止一行資料,他鎖住的是多行,是一個資料範圍。間隙鎖的主要作用是為了防止出現幻讀,但是它會把鎖定範圍擴大,在某些場景下這可能會對性能造成很大的危害。

示例:如果一個間隙被事務T1加了鎖,其它事務是不能在這個間隙插入記錄的。

session1 session2
MySQL進階 之 鎖MySQL鎖概述MyISAM表鎖(偏讀)InnoDB表鎖(偏寫)
-
-
MySQL進階 之 鎖MySQL鎖概述MyISAM表鎖(偏讀)InnoDB表鎖(偏寫)
// 等待挂起
MySQL進階 之 鎖MySQL鎖概述MyISAM表鎖(偏讀)InnoDB表鎖(偏寫)
MySQL進階 之 鎖MySQL鎖概述MyISAM表鎖(偏讀)InnoDB表鎖(偏寫)

間隙鎖的目的是為了防止幻讀,其主要通過兩個方面實作這個目的:

(1)防止間隙内有新資料被插入

(2)防止已存在的資料,更新成間隙内的資料(例如防止numer=3的記錄通過update變成number=5)

innodb自動使用間隙鎖的條件:

(1)必須在RR級别下

(2)檢索條件必須有索引(沒有索引的話,mysql會全表掃描,那樣會鎖定整張表所有的記錄,包括不存在的記錄,此時其他事務不能修改不能删除不能添加)

如何鎖定一行

FOR UPDATE僅适用于InnoDB,且必須在交易區塊(BEGIN/COMMIT)中才能生效。

假設有個表單products ,裡面有id跟name二個欄位,id是主鍵。

例1: (明确指定主鍵,并且有此記錄,row lock)

SELECT * FROM products WHERE id=’3’ FOR UPDATE;

SELECT * FROM products WHERE id=’3’ and type=1 FOR UPDATE;

例2: (明确指定主鍵,若查無此記錄,無lock)

SELECT * FROM products WHERE id=’-1’ FOR UPDATE;

例2: (無主鍵,table lock)

SELECT * FROM products WHERE name=’Mouse’ FOR UPDATE;

例3: (主鍵不明确,table lock)

SELECT * FROM products WHERE id<>’3’ FOR UPDATE;

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

SELECT * FROM products WHERE id LIKE ‘3’ FOR UPDATE;

繼續閱讀