事務(wù)
定義:ACID(atomicity Consistency Isolation Durability)
mysql開(kāi)啟事務(wù)
begin / start transaction -- 手工
commit / rollback -- 事務(wù)提交或回滾
set session autocommit = on/off; -- 設(shè)定事務(wù)是否自動(dòng)開(kāi)啟
JDBC編程:connection.setAutoCommit(boolean);
Spring 事務(wù)AOP編程:expression=execution(com.gpedu.dao.*.*(..))
事務(wù)并發(fā)帶來(lái)的問(wèn)題
- 臟讀(dirty read):如果第二個(gè)事務(wù)查詢到第一個(gè)事務(wù)還未提交的更新數(shù)據(jù),形成臟讀仲器。
image.png- 虛讀(phantom read):一個(gè)事務(wù)執(zhí)行兩次查詢会通,第二次查詢比第一次多出或少一些數(shù)據(jù),造成兩次結(jié)果不一致娄周。只是另一個(gè)事務(wù)在這兩次查詢中間插入或者刪除了數(shù)據(jù)造成的。
image.png- 不可重復(fù)讀(unrepeated read):一個(gè)事務(wù)兩次讀取同一行數(shù)據(jù)沪停,結(jié)果得到不同狀態(tài)結(jié)果煤辨,如中間正好另一個(gè)事務(wù)更新了該數(shù)據(jù),兩次結(jié)果相異木张,不可信任众辨。
image.png
事務(wù)的四種隔離級(jí)別
[SQL92 ANSI/ISO標(biāo)準(zhǔn)]
(http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt)
隔離級(jí)別 | 解決問(wèn)題 | 原理 |
---|---|---|
Read Uncommitted(未提交讀) | 未解決并發(fā)問(wèn)題 | 事務(wù)未提交對(duì)其他事務(wù)也是可見(jiàn)的,臟讀(dirty read) |
Read Committed(提交讀) | 解決臟讀問(wèn)題 | 一個(gè)事務(wù)開(kāi)始之后舷礼,只能看到自己提交的事務(wù)所做的修改鹃彻,不可重復(fù)讀(nonrepeatable read) |
Repeatable Read (可重復(fù)讀) | 解決不可重復(fù)讀問(wèn)題 | 在同一個(gè)事務(wù)中多次讀取同樣的數(shù)據(jù)結(jié)果是一樣的,這種隔離級(jí)別未定義解決幻讀的問(wèn)題 |
Serializable(串行化) | 解決所有問(wèn)題 | 最高的隔離級(jí)別妻献,通過(guò)強(qiáng)制事務(wù)的串行執(zhí)行 |
隔離級(jí)別的實(shí)現(xiàn)是通過(guò)鎖和MVCC
鎖---用于管理不同事務(wù)對(duì)于共享資源的并發(fā)訪問(wèn)
鎖的比較方面:鎖定粒度蛛株、加鎖效率、沖突概率育拨、并發(fā)性能
Innodb支持行鎖谨履,可通過(guò)鎖定所有行間接實(shí)現(xiàn)表鎖。
Innodb鎖類(lèi)型
- 共享鎖(行鎖):Shared Locks
- 排它鎖(行鎖):Exclusive Locks
- 意向鎖共享鎖(表鎖):Intention Shared Locks
- 意向鎖排它鎖(表鎖):Intention Exclusive Locks
- 自增鎖:AUTO-INC Locks
行鎖的算法- 記錄鎖 Record locks
- 間隙鎖 Gap locks
- 臨鍵鎖 Next-key locks
共享鎖:又稱(chēng)為讀鎖熬丧,簡(jiǎn)稱(chēng)S鎖笋粟,顧名思義,共享鎖就是多個(gè)事務(wù)對(duì)于同一數(shù)據(jù)可以共享一把鎖析蝴,都能訪問(wèn)到數(shù)據(jù)害捕,但是只能讀不能修改;
//加鎖釋鎖方式:
select * from users WHERE id=1 LOCK IN SHARE MODE;
commit/rollback
排他鎖:又稱(chēng)為寫(xiě)鎖,簡(jiǎn)稱(chēng)X鎖闷畸,排他鎖不能與其他鎖并存尝盼,如一個(gè)事務(wù)獲取了一個(gè)數(shù)據(jù)行的排他鎖,其他事務(wù)就不能再獲取該行的鎖(共享鎖腾啥、排他鎖)东涡,只有該獲取了排他鎖的事務(wù)是可以對(duì)數(shù)據(jù)行進(jìn)行讀取和修改冯吓,(其他事務(wù)要讀取數(shù)據(jù)可來(lái)自于快照)
//加鎖釋鎖方式:
delete / update / insert 默認(rèn)加上X鎖
SELECT * FROM table_name WHERE ... FOR UPDATE
commit/rollback
Innodb行鎖是通過(guò)給索引項(xiàng)加鎖實(shí)現(xiàn)的,只有通過(guò)索引項(xiàng)進(jìn)行數(shù)據(jù)檢索才使用行鎖疮跑,否則使用表鎖
Innodb表鎖實(shí)現(xiàn) lock tables xx read/write组贺;
意向共享鎖(IS):表示事務(wù)準(zhǔn)備給數(shù)據(jù)行加入共享鎖,即一個(gè)數(shù)據(jù)行加共享鎖前必須先取得該表的IS鎖祖娘,意向共享鎖之間是可以相互兼容的
意向排它鎖(IX):表示事務(wù)準(zhǔn)備給數(shù)據(jù)行加入排他鎖失尖,即一個(gè)數(shù)據(jù)行加排他鎖前必須先取得該表的IX鎖,意向排它鎖之間是可以相互兼容的
意向鎖(IS渐苏、IX)是InnoDB數(shù)據(jù)操作之前自動(dòng)加的掀潮,不需要用戶干預(yù)
意義:當(dāng)事務(wù)想去進(jìn)行鎖表時(shí),可以先判斷意向鎖是否存在琼富,存在時(shí)則可快速返回該表不能啟用表鎖
自增鎖(auto_inc lock):自增列自增長(zhǎng)的表級(jí)鎖
show variables like 'innodb_autoinc_lock_mode';
默認(rèn)取值1仪吧,代表連續(xù),事務(wù)未提交ID永久丟失
Next-key locks(臨鍵鎖):鎖住記錄+區(qū)間(左開(kāi)右閉)Innodb行鎖的默認(rèn)算法
?當(dāng)sql執(zhí)行按照索引進(jìn)行數(shù)據(jù)的檢索時(shí),查詢條件為范圍查找(between and鞠眉、<薯鼠、>等)并有數(shù)據(jù)命中則此時(shí)SQL語(yǔ)句加上的鎖為Next-key locks,鎖住索引的記錄+區(qū)間(左開(kāi)右閉)
劃分區(qū)間的規(guī)則:根據(jù)存在的數(shù)據(jù)將表劃分為不同的區(qū)間械蹋,如下圖:
臨鍵鎖圖示.png
臨鍵鎖=間隙鎖+記錄鎖
Gap locks(間隙鎖):鎖住數(shù)據(jù)不存在的區(qū)間(左開(kāi)右開(kāi))
?當(dāng)sql執(zhí)行按照索引進(jìn)行數(shù)據(jù)的檢索時(shí)出皇,查詢條件的數(shù)據(jù)不存在,這時(shí)SQL語(yǔ)句加上的鎖即為Gap locks哗戈,鎖住索引不存在的區(qū)間(左開(kāi)右開(kāi))---查詢區(qū)間內(nèi)不存在郊艘,臨鍵鎖退化成間隙鎖
Record locks(記錄鎖):鎖住具體的索引項(xiàng)
?當(dāng)sql執(zhí)行按照唯一性(Primary key、Unique key)索引進(jìn)行數(shù)據(jù)的檢索時(shí)唯咬,查詢條件等值匹配且查詢的數(shù)據(jù)是存在纱注,這時(shí)SQL語(yǔ)句加上的鎖即為記錄鎖Record locks,鎖住具體的索引項(xiàng)
死鎖:多個(gè)事務(wù)相互持有鎖
案例:事務(wù)a先對(duì)表1進(jìn)行操作副渴,然后事務(wù)b對(duì)表2進(jìn)行操作奈附,兩個(gè)事務(wù)都沒(méi)有提交,隨后事務(wù)a表2進(jìn)行操作煮剧,事務(wù)b對(duì)表1進(jìn)行操作斥滤,就會(huì)形成死鎖。
避免死鎖:
- 類(lèi)似的業(yè)務(wù)邏輯以固定的順序訪問(wèn)表和行勉盅。
- 大事務(wù)拆小佑颇。大事務(wù)更傾向于死鎖,如果業(yè)務(wù)允許草娜,將大事務(wù)拆小挑胸。
- 在同一個(gè)事務(wù)中,盡可能做到一次鎖定所需要的所有資源宰闰,減少死鎖概率茬贵。
- 降低隔離級(jí)別簿透,如果業(yè)務(wù)允許,將隔離級(jí)別調(diào)低也是較好的選擇
- 為表添加合理的索引解藻。不走索引將會(huì)為表的每一行記錄添加上鎖(或者說(shuō)是表鎖)