Innodb 行鎖與表鎖

2021-10-12 14:21:27 字數 3454 閱讀 4967

行鎖與表鎖

innodb預設是行級別的鎖,當有明確指定的主鍵時候,是行級鎖。否則是表級別。

#for update的注意點

for update 僅適用於innodb,並且必須開啟事務,在begin與commit之間才生效。

要測試for update的鎖表情況,可以利用mysql的command mode,開啟二個視窗來做測試。

1、只根據主鍵進行查詢,並且查詢到資料,主鍵字段產生行鎖。

begin;

select * from goods where id = 1 for update;

commit;

2、只根據主鍵進行查詢,沒有查詢到資料,不產生鎖。

begin;

select * from goods where id = 1 for update;

commit;

3、根據主鍵、非主鍵含索引(name)進行查詢,並且查詢到資料,主鍵字段產生行鎖,name欄位產生行鎖。

begin;

select * from goods where id = 1 and name='prod11' for update;

commit;

4、根據主鍵、非主鍵含索引(name)進行查詢,沒有查詢到資料,不產生鎖。

begin;

select * from goods where id = 1 and name='prod12' for update;

commit;

5、根據主鍵、非主鍵不含索引(name)進行查詢,並且查詢到資料,如果其他執行緒按主鍵字段進行再次查詢,則主鍵字段產生行鎖,如果其他執行緒按非主鍵不含索引字段進行查詢,則非主鍵不含索引字段產生表鎖,如果其他執行緒按非主鍵含索引字段進行查詢,則非主鍵含索引字段產生行鎖,如果索引值是列舉型別,mysql也會進行表鎖,這段話有點拗口,大家仔細理解一下。

begin;

select * from goods where id = 1 and name='prod11' for update;

commit;

6、根據主鍵、非主鍵不含索引(name)進行查詢,沒有查詢到資料,不產生鎖。

begin;

select * from goods where id = 1 and name='prod12' for update;

commit;

7、根據非主鍵含索引(name)進行查詢,並且查詢到資料,name欄位產生行鎖。

begin;

select * from goods where name='prod11' for update;

commit;

8、根據非主鍵含索引(name)進行查詢,沒有查詢到資料,不產生鎖。

begin;

select * from goods where name='prod11' for update;

commit;

9、根據非主鍵不含索引(stock)進行查詢,並且查詢到資料,stock字段產生表鎖。

begin;

select * from goods where stock='1000' for update;

commit;

10、根據非主鍵不含索引(stock)進行查詢,沒有查詢到資料,stock字段產生表鎖。

begin;

select * from goods where stock='2000' for update;

commit;

11、只根據主鍵進行查詢,查詢條件為不等於,並且查詢到資料,主鍵字段產生表鎖。

begin;

select * from goods where id <> 1 for update;

commit;

11.1

begin;

select * from goods where id < 5 and id <> 1 for update;

commit;

這條查詢僅僅會返回2 ~ 4之間的行,但是實際上獲取了 1 ~ 4之間的行的排他鎖。innodb會鎖住第1行  ---- 底層儲存引擎的操作是「從索引的開頭開始獲取滿足條件id < 5的記錄」 ,伺服器並沒有告訴innodb可以過濾第1行的where條件, 需要mysql伺服器將儲存引擎返回行以後再應用where過濾條件(extra  using where)。

12、只根據主鍵進行查詢,查詢條件為不等於,沒有查詢到資料,主鍵字段產生表鎖。

begin;

select * from goods where id <> 1 for update;

commit;

13、只根據主鍵進行查詢,查詢條件為 like,並且查詢到資料,主鍵字段產生表鎖。

begin;

select * from goods where id like '1' for update;

commit;

14、只根據主鍵進行查詢,查詢條件為 like,沒有查詢到資料,主鍵字段產生表鎖。

begin;

select * from goods where id like '1' for update;

commit;

總結

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

2、由於mysql的行鎖是針對索引加的鎖,不是針對記錄加的鎖,所以雖然是訪問不同行的記錄,但是如果是使用相同的索引鍵,是會出現鎖衝突的。應用設計的時候要注意這一點。

3、當表有多個索引的時候,不同的事務可以使用不同的索引鎖定不同的行,另外,不論是使用主鍵索引、唯一索引或普通索引,innodb都會使用行鎖來對資料加鎖。

4、即便在條件中使用了索引字段,但是否使用索引來檢索資料是由mysql通過判斷不同執行計畫的代價來決定的,如果mysql認為全表掃瞄效率更高,比如對一些很小的表,它就不會使用索引,這種情況下innodb將使用表鎖,而不是行鎖。因此,在分析鎖衝突時,別忘了檢查sql的執行計畫,以確認是否真正使用了索引。

5、檢索值的資料型別與索引字段不同,雖然mysql能夠進行資料型別轉換,但卻不會使用索引,從而導致innodb使用表鎖。通過用explain檢查兩條sql的執行計畫,我們可以清楚地看到了這一點。(此條本地驗證後發現 資料庫型別為varchar時 查詢用 數字型別時用不了索引 。但資料庫型別為int、  datetime時 查詢型別為字串 也可以走索引)

Mysql行鎖與表鎖

用主鍵修改就是行瑣,或者用索引修改就是行瑣 update tab set name xx where id xx 行鎖 update tab set name xx where date 非主鍵或索引 xx 表鎖 插入的時候呢?插入都是行鎖 alert語句修改表結構,表鎖 表鎖和行鎖同時發生時,會等...

mysql 行鎖與表鎖

為日常整理,可能會有些重複.行鎖表表鎖 1 多個事務操作同一行資料時,後來的事務處於阻塞等待狀態。這樣可以避免了髒讀等資料一致性的問題。後來的事務可以操作其他行資料,解決了表鎖高併發效能低的問題。2 innodb的行鎖是針對索引加的鎖,不是針對記錄加的鎖。並且該索引不能失效,否則都會從行鎖公升級為表...

Oracle表鎖與行鎖

1 登入資料所在的資料庫 用管理員賬戶登入 2 查詢是否存在鎖表的sql 3 進行表鎖sql 共享方式的表級鎖 share lock table 表 表 inshare mode nowait lock table test user in share mode 獨佔方式表級鎖 exclusive ...