MySql事務在併發情況下出現的異常及解決方法

數據庫併發操作會引發的問題

多個事務背景:MySQL5.6 InnoDB存儲引擎,事務隔離級別最低的read uncommited(爲了看到各種異常)。
多個事務同時訪問數據庫時候,會發生下列5類問題,包括3類數據讀問題(髒讀,不可重複讀,幻讀),2類數據更新問題(第一類丟失更新,第二類丟失更新):

髒讀(dirty read)

A事務讀取B事務尚未提交的更改數據,並在這個數據基礎上操作。如果B事務回滾,那麼A事務讀到的數據根本不是合法的,稱爲髒讀。在oracle中,由於有version控制,不會出現髒讀。數據庫事務隔離級別高於 read commited即可

實際庫存應當有9個,但由於髒讀,現有8個
理論庫存應當有9個,但由於髒讀(T4時查出庫存9個即爲髒讀),現有8個
不可重複讀(unrepeatable read)

 A事務讀取了B事務已經提交的更改(或刪除)數據。比如A事務第一次讀取數據,然後B事務更改該數據並提交,A事務再次讀取數據,兩次讀取的數據不一樣。將數據庫事務隔離級別設爲repeatable read即可

在這裏插入圖片描述
事務A在T2和T4讀出的數據不同,即是不可重複度

幻讀(phantom read)

A事務讀取了B事務已經提交的新增數據。注意和不可重複讀的區別,這裏是新增,不可重複讀是更改(或刪除)。這兩種情況對策是不一樣的,對於不可重複讀,只需要採取行級鎖防止該記錄數據被更改或刪除,然而對於幻讀必須加表級鎖,防止在這個表中新增一條數據(PS:對於鎖的問題請自行查找或關注我的後續文章)。
當然,也可以將數據庫事務隔離級別設爲serializable,但一般不這樣做,因爲該策略是完全阻塞的,將對數據庫的訪問完全序列化,併發性能最差。

在這裏插入圖片描述
T5時數據莫名其妙有了,就是幻讀現象。如果A事務只進行讀操作,不進行寫操作,將數據庫事務隔離級別設爲repeatable read,並用start transaction with consistent snapshot開啓事務,同時進行快照讀,也可以防止幻讀現象(因爲在可重讀策略下,不是開啓事務就建立快照點,而是在第一次查詢時建立快照點)。
丟失更新

 第一類丟失更新:A事務提交時,把已提交的B事務的數據覆蓋掉。
 第二類丟失更新:A事務回滾時,把已提交的B事務的數據覆蓋掉。  

第一類
在這裏插入圖片描述
理論庫存是7個,但現在剩餘8個;
第二類
在這裏插入圖片描述
理論庫存是9個,但現在剩餘10個;
丟失更新完全靠事務是無法解決的,此時就需要結合數據庫悲觀鎖來防止此類問題,操作如下:
//0.開始事務

begin;/begin work;/start transaction; (三者選一就可以)

//1.查詢出商品信息

select status from t_goods where id=1 for update;(添加排他鎖)

//2.根據商品信息生成訂單

insert into t_orders (id,goods_id) values (null,1);

//3.修改商品status爲2

update t_goods set status=2;

//4.提交事務

commit;/commit work;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章