1. 程式人生 > >遇到mysql資料庫事務隔離級別相關的小坑

遇到mysql資料庫事務隔離級別相關的小坑

幾乎所有軟體工程師都知道,mysql有4種事務隔離級別,但是實際開發過程中可能有時候忽略這個小細節,有時候可能是本來就沒有考慮過,有時候也可能是其他的原因,比如我這次踩到的小坑。

事情還原: 1、需求一:是新建一個商戶,但是客戶要求在建立商戶的時候要預設給他們開一個管理員賬戶。其實很簡單,就是新建一個商戶,然後再新建一個賬戶,賬戶表中有一個欄位關聯商戶。但是一看資料庫隔離級別,是Read Committed(讀取提交內容)。當時想著,算了,應該是其他專案需求需要用到這樣的隔離級別,就先建立商戶,然後再新建賬戶。當然,這就免不了各種錯誤處理。 2、需求二:每個使用者會有一個預設收貨地址,如果新增或者更新一個收貨地址,且設定為預設的,那麼需要將其他收貨地址設定為非預設收貨地址。受到需求一的影響。沒看資料庫隔離級別,就直接按照Read Committed(讀取提交內容)這種隔離級別的方式開發,先插入(或者更新),如果是預設地址,將所有查出該使用者所有的收貨地址,將預設地址修改為非預設的地址。

結果: 如果需求一和需求二是在同一個資料庫中的時候,其實是沒問題的。因為事務隔離級別一致。但是剛好運維那邊給開發遷移資料庫的過程中,由於各種原因,事務隔離級別從Read Committed(讀取提交內容)修改為Repeatable Read(可重讀),這就會導致需求二中新插入或者更新的時候,會把先插入或者更新的記錄被讀取到,然後修改了。

教訓: 1、特定的專案對於的資料庫,最好約定好用同一種事務隔離級別。(這次採坑有個原因是同一個資料庫,有多個專案一起用) 2、如果1條件不滿足,最好在使用事務前設定會話對應的事務隔離級別

設定會話隔離級別: 檢視InnoDB儲存引擎 系統級的隔離級別 和 會話級的隔離級別:

mysql> select @@global.tx_isolation,@@tx_isolation;
+-----------------------+-----------------+
| @@global.tx_isolation | @@tx_isolation  |
+-----------------------+-----------------+
| REPEATABLE-READ       | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.00 sec)

設定innodb的事務級別方法是:set 作用域 transaction isolation level 事務隔離級別,例如~

SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}

mysql> set global transaction isolation level read committed; //全域性的

mysql> set session transaction isolation level read committed; //當前會話

基礎知識: SQL標準定義了4類隔離級別,包括了一些具體規則,用來限定事務內外的哪些改變是可見的,哪些是不可見的。低級別的隔離級一般支援更高的併發處理,並擁有更低的系統開銷。 Read Uncommitted(讀取未提交內容)

   在該隔離級別,所有事務都可以看到其他未提交事務的執行結果。本隔離級別很少用於實際應用,因為它的效能也不比其他級別好多少。讀取未提交的資料,也被稱之為髒讀(Dirty Read)。

Read Committed(讀取提交內容)

   這是大多數資料庫系統的預設隔離級別(但不是MySQL預設的)。它滿足了隔離的簡單定義:一個事務只能看見已經提交事務所做的改變。這種隔離級別 也支援所謂的不可重複讀(Nonrepeatable Read),因為同一事務的其他例項在該例項處理其間可能會有新的commit,所以同一select可能返回不同結果。

Repeatable Read(可重讀)

   這是MySQL的預設事務隔離級別,它確保同一事務的多個例項在併發讀取資料時,會看到同樣的資料行。不過理論上,這會導致另一個棘手的問題:幻讀 (Phantom Read)。簡單的說,幻讀指當用戶讀取某一範圍的資料行時,另一個事務又在該範圍內插入了新行,當用戶再讀取該範圍的資料行時,會發現有新的“幻影” 行。InnoDB和Falcon儲存引擎通過多版本併發控制(MVCC,Multiversion Concurrency Control)機制解決了該問題。

Serializable(可序列化) 這是最高的隔離級別,它通過強制事務排序,使之不可能相互衝突,從而解決幻讀問題。簡言之,它是在每個讀的資料行上加上共享鎖。在這個級別,可能導致大量的超時現象和鎖競爭。