1.MySql中的鎖
- 表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖衝突的概率最高,併發度最低。表級鎖更適合於以查詢爲主,只有少量按索引條件更新數據的應用,如 OLAP (Online analytical processing,聯機分析處理)系統。
- 行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的概率最低,併發度也最高。行級鎖則更適合於有大量按索引條件併發更新少量不同數據,同時又有併發查詢的應用,如一些OLTP(On-Line Transaction Processing:聯機事務處理)系統。
- 頁面鎖(gap 鎖,間隙鎖):開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,併發度一般。
2.MyISAM 鎖
表共享讀鎖(Table Read Lock)
- 語法:lock table 表名 READ,unlock tables;解鎖
lock table testmysam READ
- 讀鎖,對 MyISAM 表的讀操作,不會阻塞當前 session/其他session對同一表的讀請求,但會阻塞對同一表的寫請求;當前session更新或訪問讀其他表都會提示錯誤(查詢被鎖的表不能使用別名,否則也會被鎖)
表獨佔寫鎖(Table Write Lock)
- 語法:lock table 表名 WRITE;unlock tables;解鎖
lock table testmysam WRITE
- 寫鎖,對 MyISAM 表的寫操作,則會阻塞其他會話對同一表的讀和寫操作,當前 session 可以對本表做 CRUD,但對其他表進行操作會報錯
3.InnoDB 鎖
共享鎖
-
又稱讀鎖。當一個事務對某幾行上讀鎖時,允許其他事務對這幾行進行讀操作,但不允許其進行寫操作,也不允許其他事務給這幾行上排它鎖,但允許上讀鎖。
-
語法:select * from 表where 條件lock in share mode;
排它鎖
- 又稱寫鎖。當一個事務對某幾個上寫鎖時,不允許其他事務寫,但允許讀。更不允許其他事務給這幾行上任何鎖。
- 語法:select * from 表where 條件for update;
注意
1.兩個事務不能鎖同一個索引的同一部分值,另一個等待。
2.insert ,delete , update 在事務中都會自動默認加上排它鎖。即使後面沒加for update
3.行鎖必須有索引才能實現,否則會自動鎖全表,那麼就不是行鎖了。
排查
查看鎖以及被鎖數據:
mysql5.6&mysql5.7:
select * from information_schema.INNODB_LOCKS;
Mysql8:
SELECT * from performance_schema.data_locks;
查看具體要kill的線程號:
mysql5.7&mysql8:
select * from sys.innodb_lock_waits;
mysql5.6:
SELECT
r.trx_id waiting_trx_id,r.trx_mysql_thread_id waiting_thread,
r.trx_query waiting_query,
b.trx_id blocking_trx_id,
b.trx_mysql_thread_id blocking_thread
FROM
information_schema.innodb_lock_waits w
INNER JOIN
information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id
INNER JOIN
information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id;
4.查看支持事務的存儲引擎
show engines; --只有InnoDB
show variables like '%storage_engine%'; --查看默認存儲引擎
show create table 表名; --查看某張表使用的存儲引擎
5.事務特性
原子性(atomicity)
一個事務必須被視爲一個不可分割的最小單元,整個事務中的所有操作要麼全部提交成功,
要麼全部失敗,對於一個事務來說,不可能只執行其中的一部分操作
一致性(consistency)
一致性是指事務將數據庫從一種一致性轉換到另外一種一致性狀態,在事務開始之前和事務
結束之後數據庫中數據的完整性沒有被破壞
持久性(durability)
一旦事務提交,則其所做的修改就會永久保存到數據庫中。此時即使系統崩潰,已經提交的
修改數據也不會丟失
隔離性(isolation)
一旦事務提交,則其所做的修改就會永久保存到數據庫中。此時即使系統崩潰,已經提交的
修改數據也不會丟失
- 未提交讀(READ UNCOMMITED)髒讀
- 已提交讀(READ COMMITED)不可重複讀
- 可重複讀(REPEATABLE READ)
- 可串行化(SERIALIZABLE)
show variables like '%tx_isolation%'; --默認RR可重複讀
未提交讀(READ UNCOMMITED)
會引起髒讀,不可重複讀,幻讀
set SESSION TRANSACTION ISOLATION LEVEL read UNCOMMITTED;
已提交讀(READ COMMITED)
解決髒讀,會引起不可重複讀,幻讀
set SESSION TRANSACTION ISOLATION LEVEL read committed;
可重複讀(REPEATABLE READ)
解決不可重複讀,會引起幻讀
mysql默認隔離級別,通過間隙鎖解決幻讀問題
set SESSION TRANSACTION ISOLATION LEVEL repeatable read;
可串行化(SERIALIZABLE)
解決幻讀
set SESSION TRANSACTION ISOLATION LEVEL serializable;
間隙鎖(gap鎖)
select @@tx_isolation;
create table t_lock_1 (a int primary key);
insert into t_lock_1 values(10),(11),(13),(20),(40);
對於主鍵索引:
一個會話中:
begin;
select * from t_lock_1 where a <= 13 for update;
另一個會話中
insert into t_lock_1 values(21) --成功
insert into t_lock_1 values(19) --阻塞
where id <=x for update;
mysql5.7中:掃描到值x在表中的下一個值爲止,都不可改,(-無窮,下一個值]
mysql8中:掃描到當前值x 都不可改
where id in (a,b) for update;
mysql5.7中:整張表不可改
Mysql8.0中:只有in條件中的數據不可改
非主鍵上的索引:
create table t_lock_2 (a int primary key,b int, key (b));
insert into t_lock_2 values(1,1),(3,1),(5,3),(8,6),(10,8);
一個會話中:
BEGIN;
select * from t_lock_2 where b=3 for update;
另一個會話中:
select * from t_lock_2 where a = 5 lock in share mode; -- 不可執行,因爲a=5 上有一把記錄鎖
insert into t_lock_2 values(4, 2); -- 不可以執行,因爲b=2 在(1, 3]內
insert into t_lock_2 values(6, 5); -- 不可以執行,因爲b=5 在(3, 6)內
insert into t_lock_2 values(2, 0); -- 可以執行,(2, 0)均不在鎖住的範圍內
insert into t_lock_2 values(6, 7); -- 可以執行,(6, 7)均不在鎖住的範圍內
insert into t_lock_2 values(9, 6); -- 可以執行
insert into t_lock_2 values(7, 6); -- 不可以執行
鎖住值x對應的主鍵id對應不可改
非主鍵索引鎖得是[上一個值,下一個值]
6.事務語法
開啓事務
begin;
START TRANSACTION;
begin work;
事務回滾
rollback;
事務提交
commit;
還原點
savepoint
show variables like '%autocommit%'; --自動提交事務是開啓的
set autocommit=0;
insert into testdemo values(5,5,5);
savepoint s1;
insert into testdemo values(6,6,6);
savepoint s2;
insert into testdemo values(7,7,7);
savepoint s3;
select * from testdemo
rollback to savepoint s2
rollback