我是????廖志偉????,一名????Java開發工程師????、????Java領域優質創作者????、????CSDN部落格專家????、????幕後大佬社群創始人????。擁有多年一線研發經驗,研究過各種常見架構及中間件的底層源碼,對于大型分布式、微服務、三高架構(高性能、高并發、高可用)有過實踐架構經驗。
文章目錄
- 髒讀
- 不可重複讀
- 幻讀
- 資料庫事務隔離級别
- Read uncommitted 讀未送出
- Read committed 讀送出
- Repeatable read 重複讀
- Serializable 序列化
本文内容:

髒讀
一個事務a修改或添加了一條資料,在a事務送出之前,另一個事務b讀到了這條資料,并進行了操作。a如果復原的話,髒讀可能會導緻b操作不存在的資料。
不可重複讀
在一次事務中的兩次相同條件的查詢不一緻,比如a事務執行select count(*) from user where name=‘alex’ 這時事務b插入了一條資料name=alex并送出這就會導緻事務a第二次查詢的時候多了一個計數
幻讀
事務a與事務b是完全隔離的,事務a執行’select id from user得到的id為1和2.這個時候b事務在user表中添加了一條資料id=3并送出,然後事務a想添加一條id為3的資料,如果id是唯一的,那a就會發現插不進去并提示dumplicate entry 3 for key id,原因是事務a阻止事務b的插入行為。
資料庫事務隔離級别
Read uncommitted 讀未送出
公司發工資了,上司把20000元打到廖志偉的賬号上,但是該事務并未送出,而廖志偉正好去檢視賬戶,發現工資已經到賬,是20000元整,非常高興。可是不幸的是,上司發現發給廖志偉的工資金額不對,是16000元,于是迅速修改金額,将事務送出,最後廖志偉實際的工資隻有16000元,廖志偉空歡喜一場。
出現上述情況,即我們所說的髒讀,兩個并發的事務,“事務A:上司給廖志偉發工資”、“事務B:廖志偉查詢工資賬戶”,事務B讀取了事務A尚未送出的資料。當隔離級别設定為Read uncommitted時,就可能出現髒讀,如何避免髒讀,請看下一個隔離級别。
Read committed 讀送出
廖志偉拿着工資卡去消費,系統讀取到卡裡确實有2000元,而此時她的老婆也正好在網上轉賬,把廖志偉工資卡的2000元轉到另一賬戶,并在廖志偉之前送出了事務,當廖志偉扣款時,系統檢查到廖志偉的工資卡已經沒有錢,扣款失敗,廖志偉十分納悶,明明卡裡有錢,為何…
出現上述情況,即我們所說的不可重複讀,兩個并發的事務,“事務A:廖志偉消費”、“事務B:廖志偉的老婆網上轉賬”,事務A事先讀取了資料,事務B緊接了更新了資料,并送出了事務,而事務A再次讀取該資料時,資料已經發生了改變。當隔離級别設定為Read committed時,避免了髒讀,但是可能會造成不可重複讀。大多數資料庫的預設級别就是Read committed,比如Sql Server , Oracle。如何解決不可重複讀這一問題,請看下一個隔離級别。
Repeatable read 重複讀
當廖志偉拿着工資卡去消費時,一旦系統開始讀取工資卡資訊(即事務開始),廖志偉的老婆就不可能對該記錄進行修改,也就是廖志偉的老婆不能在此時轉賬。這就避免了不可重複讀。廖志偉的老婆工作在銀行部門,她時常通過銀行内部系統檢視廖志偉的信用卡消費記錄。有一天,她正在查詢到廖志偉當月信用卡的總消費金額(select sum(amount) from transaction where month = 本月)為80元,而廖志偉此時正好在外面胡吃海喝後在收銀台買單,消費1000元,即新增了一條1000元的消費記錄(insert transaction … ),并送出了事務,随後廖志偉的老婆将廖志偉當月信用卡消費的明細列印到A4紙上,卻發現消費總額為1080元,廖志偉的老婆很詫異,以為出現了幻覺,幻讀就這樣産生了。當隔離級别設定為Repeatable read時,可以避免不可重複讀,但會出現幻讀。注:MySQL的預設隔離級别就是Repeatable read。
Serializable 序列化
Serializable是最高的事務隔離級别,同時代價也花費最高,性能很低,一般很少使用,在該級别下,事務順序執行,不僅可以避免髒讀、不可重複讀,還避免了幻像讀。
總結