(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 不支援事務,不支援外來鍵,鎖機制為表鎖,有較高的插入和查詢 原子...