鎖 mysql
select * from t_user where name = 'xx' lock in share mode 獲取目標集共享鎖後,執行查詢
select * from t_user where name = 'xx' for update
獲取目標集排他鎖後,執行查詢
1 #準備數據 2 create table t_deadlock( 3 id int not null auto-increment, 4 name varchar(20), 5 type int, 6 key (type), 7 primary key (id) 8 ); 9 10 insert into t_deadlock (name,type) VALUES ('zs',1); 11 insert into t_deadlock (name,type) VALUES ('ls',2); 12 insert into t_deadlock (name,type) VALUES ('ww',3);
1 # 需求: 對zs的type作加1操做, 爲防⽌資源搶奪(更新丟失), 設置鎖 2 --事務1------------- 3 begin; 4 select type from t_deadlock where name='zs' lock in share mode; # 共享鎖 5 --事務2------------- 6 begin; 7 select type from t_deadlock where name='zs' lock in sharemode; # 共享鎖 8 --事務1------------- 9 update t_deadlock set type=2 where name='zs'; # 等待事務2釋放共享鎖 10 -事務2------------- 11 update t_deadlock set type=2 where name='zs'; # 等待事務1釋放共享鎖 12 # 相互等待, 產生死鎖
1 #更新丟失的解決方法: 2 1.使用update子查詢更新(樂觀鎖) 3 update t_deadlock set type=type+1 where name='zs'; 4 2.查詢時直接使用排它鎖(悲觀鎖) 5 select type from t_deadlock where name='zs' for update;
1 # 需求: 記錄的數量=3,才插入一條數據 2 --事務1------------- 3 begin; 4 select count(*) from t_deadlock; # 獲取記錄數量爲3 5 --事務2------------- 6 begin; 7 select count(*) from t_deadlock; # 獲取記錄數量爲3 8 --事務1------------- 9 insert into t_deadlock (name, type) values ('zl', 1); 10 commit; # 插入成功 11 --事務2------------- 12 insert into t_deadlock (name, type) values ('fq', 1); 13 commit; # 插入成功, 結果插入了兩條數據
1 # 併發插⼊的解決辦法: insert後邊不能直接鏈接where, 而且insert只鎖對應的行, 2 不鎖表, 不會影響併發的插入操做(沒法使用樂觀鎖完成需求), 只能在查詢時就手動設置 3 排它鎖(悲觀鎖) 4 --事務1------------- 5 begin; 6 select count(*) from t_deadlock for update; # 獲取記錄數量爲3 7 --事務2------------- 8 begin; 9 select count(*) from t_deadlock for update; # 等待獲取排它鎖 10 --事務1------------- 11 insert into t_deadlock (name, type) values ('zl', 1) 12 commit; # 插入成功 13 --事務2------------- 14 select count(*) from t_deadlock for update; # 事務1完成, 獲取到記錄數量爲4, 再也不執行插入操做
1 #gap鎖場景1:使用範圍條件 2 3 begin; #事務1 4 select * from t_user where age<30 for update; 5 #若是此時事務2插入記錄(age<30),則會阻塞 (age不是索引觸發表鎖,age是索引觸發的是間隙鎖) 6 7 #gap鎖場景2:鎖定索引的先後區間 [prev,next) 8 update t_user set name='lisi' where age=30; 9 #若是age爲索引,且數據中最接近age=30的值爲20和40,則age=[20,40)的範圍也會被鎖定
1 #查看隔離級別 2 select @@global.tx_isolation, @@session.tx_isolation; 3 4 #設置隔離級別(重啓後會重置) 5 SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL [READ 6 UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE] 7 8 #修改配置文件設置隔離級別(重啓不重置) 9 [mysqld] 10 transaction-isolation = READ-COMMITTED