事務1將隔離級別設定成 未提交讀,事務2隔離級別為任意級別;
事務1開啟事務,查詢賬戶資訊,查到id為1的賬號餘額為1000,id為2的餘額為1000;
事務2開啟事務,將id為1的賬戶餘額修改為2000;
事務1再次查詢賬戶資訊,發現與之前查詢的不一致了(此時事務2還未結束)。
上述便是髒讀現象。
事務1將隔離級別設定成 提交讀,事務2沒有顯示的開啟事務,關閉事務;
事務1開啟事務,查詢賬戶資訊,查到id為1的賬號餘額為1000,id為2的餘額為1000;
事務2將id為1的賬戶餘額修改為2000,因為沒有顯示開啟事務,所以這條sql語句就是一個事務,事務2已經提交;
事務1再次查詢賬戶資訊,發現與之前查詢的不一致了。
上述便是不可重複讀現象。
事務1將隔離級別設定成可重複讀,事務2沒有顯示的開啟事務,關閉事務;
事務1開啟事務,查詢賬戶資訊,查到id為1的賬號餘額為1000,id為2的餘額為1000;
事務2插入一條id為3,餘額為1000的資料,因為沒有顯示開啟事務,所以這條sql語句就是一個事務,事務2已經提交;
事務1再次插入id為3,餘額為5000的資料,發現id為3的資料已經存在了,報了主鍵重複。
上述便是幻讀現象。
加鎖避免幻讀
因為事務1要新增id為3的資料,可以給不存在的這條資料查詢時加一把鎖,事務2新增時就會阻塞。
序列讀隔離級別避免幻讀
讀取最新提交的資料
當前讀本質上是基於鎖的並行讀操作。
讀取某一個快照建立時(可以理解為某一時間點)的資料,也稱為一致性讀。
快照讀主要體現在 select (不帶for update)的語句執行時;不同隔離級別下,select 的行為不同。
在 Serializable 隔離級別下 —— 普通 select 的sql語句也會變成當前讀,即加共用讀鎖;
在 RC 隔離級別下 - 每次 select 都會建立新的快照;
在 RR 隔離級別下
快照讀本質上讀取的是歷史資料(原理是回滾段),屬於無鎖查詢。
事務1在第一次查詢時建立快照;事務2雖然修改了id為1資料,但是RR下是基於快照讀,是讀到的快照建立時的資料;
如果快照建立比update完會怎樣呢?
事務2先提交了update,事務1select時建立快照,就會讀到事務2修改的資料。
如果想要事務啟動時建立快照,需要新增with consistent snapshot;
雖然表面上事務2比事務1的select先執行,但是事務1開啟事務並建立快照先開始,讀到的是未修改的資料;
事務2基於舊資料修改了資料,會重新建立快照,事務1再更新,會基於2000進行修改。