關於MySQL鎖的一些試驗

2021-08-08 16:14:31 字數 4193 閱讀 6370

(1)、共享鎖,也叫讀鎖,當前事務可以進行讀寫操作,而其他事務只能進行讀操作,不能寫操作,禁止其他事務對同樣的資料集加排他鎖,但允許加共享鎖。

如:select * from user where email = '[email protected]' lock in share mode   

(2)、排他鎖,只允許當前事務進行讀、寫操作,在此事務結束之前,其他事務只能進行讀操作,寫操作阻塞,等待鎖的釋放,且不能再加任何鎖。

如:select * from user where email = '[email protected]' for update

開啟兩個sqlyog視窗,即兩個session,分別模擬兩個事務。新建user表,採用innodb引擎,

create table user (

id varchar(50) not null,

phone varchar(12) not null default '',

email varchar(30),

password varchar(32) not null,

*** smallint(1) not null default 1,

birth date,

num varchar(50) not null,

primary key(id)

)engine=innodb charset=utf8;

(1)、

查詢條件只有索引列

alter table user add index (email)     -->對email欄位新增普通索引

session1:

set autocommit = 0  -->避免自動提交,開啟事務

select * from user where email = '[email protected]' in share mode

此時innodb對指定的資料集加上共享鎖,是行鎖,在共享鎖事務內是強烈不建議做寫操作,如果非要寫,必須能保證其他事務不對相關的資料集做寫操作,否則死鎖。。。

update user set num = '116119' where email = '[email protected]' -->實施更新操作,發生在session2的更新操作之前
session2:

set autocommit = 0  -->避免自動提交,開啟事務

select * from user where email = '[email protected]' -->普通查詢,不阻塞,通過mvcc(多版本併發控制)實現

update user set num = '116117' where email = '[email protected]' -->對加了共享鎖的資料集進行更新操作,需要加排他鎖,會遇到阻塞

update user set password = '555555' where email = '[email protected]' -->如果更新沒有加共享鎖的資料集,排他鎖不受阻塞

在session2執行完更新操作事務之後,session1再次讀取email = '[email protected]'的記錄,還是之前的記錄,並沒有出現「不可重複讀」,如果是刪除操作也是如此。

上面的寫操作中,查詢語句用到了email,email是索引列,mysql的行級鎖是基於索引列的,不管是主鍵索引、唯一索引還是普通索引都可以,如果session2的更新操作中,查詢語句不包含索引列的話,就會全表掃瞄,採用的表級鎖,這時寫操作就會出現鎖阻塞,比如:

update user set num = '116118' where num = '100000008'  -->num欄位沒有新增索引
最後session1執行commit,session2阻塞釋放,更新操作得以執行,session1的更新操作被session2覆蓋,這是session1的更新操作在session2之前的情況,如果反過來的話,就會出現死鎖,所以盡量不要在共享鎖的事務內執行寫操作,除非可以保證其他事務不會對相同的資料集執行寫操作;如果非要執行寫操作,就要加上排他鎖 for update

(2)、

查詢條件沒有索引列

alter table user drop index email  -->刪除email欄位的普通索引

session1:

set autocommit = 0 -->避免自動提交,開啟事務

select * from user where email = '[email protected]' lock in share mode -->加上共享鎖,此時innodb對整個表加上共享鎖,是表鎖

session2:

update user set password = '555555' where email = '[email protected]'  -->此時所有資料集都會阻塞,即便不是被session1加上共享鎖的資料集

(3)、

查詢條件既有索引列,又有非索引列

alter table user add index (email)     -->再次對email欄位新增普通索引

session1:

set autocommit = 0 

select * from user where email = '[email protected]' and num='www88811' for update

session2分為以下幾種情況:

session2:

set autocommit = 0 

select * from user where email = '[email protected]' and num='8' for update

雖然session1和session2查詢的是不同的記錄,但是session1與session2用的是同樣的索引鍵email=『[email protected]』,session2同樣阻塞

session2:

set autocommit = 0 

select * from user where email = '[email protected]' and num='9' for update

相比於上一種情況,資料集不同、且索引鍵不同,不阻塞

session2:

alter table user add unique(phone)  -->給phone欄位加唯一索引

update user set num = 'www888' where phone = '13677552093'

由於phone是唯一索引列,加指定資料集加排他鎖,是行鎖,由於鎖的資料集不同,不阻塞,當然,如果資料集相同當然阻塞

------------------------------

session2:

set autocommit = 0 

select * from user where phone = '1377877098' and city='100000002' for update

與上一種情況相比,多了乙個非索引的查詢項,資料集不同、且索引鍵不同,不阻塞

------------------------------

session2:

set autocommit = 0 

select * from user where city='100000002' for update

由於查詢條件沒有索引項,鎖住全表,必然阻塞

1、innodb的鎖依賴於索引,如果查詢條件有索引列,就是行級鎖,若沒有索引列,就會是表級鎖,這是對分析鎖的衝突很有幫助

2、在共享鎖事務內,不要執行寫操作,否則大概率死鎖

MYSQL 關於鎖的一些事

現在的mysql預設的資料引擎都是innodb的,查詢操作不會出現鎖的問題 使用的快照原理 如果你的mysql的資料引擎用的是myisam,查詢時會產生鎖的,如果系統的併發量較大容易出現超時的情況,極端情況下會使搞掛rds,讓你看著cup直冒冷汗。遇到問題可以按照以下步驟來一波,問題就能迎刃而解了 ...

關於Oracle鎖的一些總結

煙一支一支地點 酒一杯一杯的幹 請你要體諒我 我酒量不好別給我挖坑 不時會遇到,不小心把錶鎖住的情況。再此,相對oracle鎖相關的知識做一些粗淺的總結。當不小心鎖表時 1 查詢session被鎖的sql,簡要查詢,得到sid select object name,machine,s.sid,s.s...

關於mysql的一些總結

首先談一下mysql常用兩種儲存引擎 myisam,innodb。需要注意的是目前mysql預設的儲存引擎為innodb 檢視mysql預設儲存引擎的命令如下 接下來簡單記錄一下mysql的myisam和innodb特點 myisam 不支援事務,不支援外來鍵,鎖機制為表鎖,有較高的插入和查詢 原子...