對MySQL併發問題及隔離級別的一些理解

數據庫併發問題

髒讀

事務A讀取到了事務B未提交的數據,當事務B回滾後,事務A讀取到的就是髒數據。

不可重複讀

同一事務在事務內多次讀取,讀取到的數據不一致。例:在事務A的第一次讀取和第二次讀取中間,事務B更新或刪除了數據,導致事務A兩次讀取到不同的數據,即不可重複讀。

幻讀

同一事務在事務內多次讀取,讀取到的記錄數不一樣。例:在事務A的第一次讀取和第二次讀取中間,事務B插入了新的記錄(此記錄符合事務A的查詢條件),導致事務A讀取到的記錄數不一樣,即幻讀。

數據庫隔離級別

MySQL數據庫有4種隔離級別,隔離級別依次遞增,相應的系統開銷也依次遞增。

未提交讀:Read uncommitted

mysql> set [global|session] transaction isolation level read uncommitted;

本事務讀取了別的事務未提交的數據,即髒讀。下面以併發的A事務和B事務對銀行賬戶的金額操作進行說明:

A事務

B事務

查詢餘額

mysql> select money from t_account where id=1234567;

+-------+
| money |
+-------+
| 10000 |
+-------+
1 row in set (0.01 sec)

 

 

開啓事務

mysql>start transaction;

 

更新餘額

mysql> update t_account set money=10001 where id=1234567;

開啓事務

mysql> start transaction;

 

查詢餘額

mysql> select money from t_account where id=1234567;

+-------+
| money |
+-------+
| 10001 |
+-------+
1 row in set (0.01 sec)

回滾事務

mysql> rollback;

其它事務操作

mysql> 

 

提交事務

mysql> commit;

從上面表格可以看出,B事務在A事務更新了餘額且未提交事務時,讀取到了髒數據money=10001。

由於可以讀到別的事務未提交的數據,所以同樣會有不可重複讀和幻讀的情況發生,此隔離級別很少用於實際應用中。

已提交讀:Read committed

mysql> set [global|session] transaction isolation level read committed;

本事務只能讀取到別的事務提交後的數據。即事務未提交時,處於中間狀態(不一致狀態)的數據對其它事務是不可見的。下面以併發的A事務和B事務對銀行賬戶的金額操作進行說明:

A事務

B事務

查詢餘額

mysql> select money from t_account where id=1234567;

+-------+
| money |
+-------+
| 10000 |
+-------+
1 row in set (0.01 sec)

 

 

開啓事務

mysql>start transaction;

 

更新餘額

mysql> update t_account set money=10001 where id=1234567;

開啓事務

mysql> start transaction;

 

查詢餘額

mysql> select money from t_account where id=1234567;

+-------+
| money |
+-------+
| 10000 |
+-------+
1 row in set (0.01 sec)

提交事務

mysql> commit;

 

 

查詢餘額

mysql> select money from t_account where id=1234567;

+-------+
| money |
+-------+
| 10001 |
+-------+
1 row in set (0.01 sec)

 

提交事務

mysql> commit;

從上面表格可以看出,B事務第一次查詢餘額時,A事務還未提交,所以讀到的數據仍是A事務開始前的值money=10000。當B事務第二次查詢餘額時,此時A事務已提交,B事務讀到的數據亦是A事務更新後的數據,即money=10001。

已提交讀避免了髒讀的情況,但仍然有不可重複讀和幻讀的情況發生。

可重複讀:Repeatable read

mysql> set [global|session] transaction isolation level repeatable read;

對同一數據的多次讀取,結果是一致的,除非數據被自身事務所修改。可重複讀可以阻止髒讀和不可重複讀,但仍然有幻讀的情況發生。

可序列化:Serializable

mysql> set [global|session] transaction isolation level serializable;

最高的隔離級別,完全服從ACID的隔離級別。所有事務依次逐個執行,這樣事務之間就完全不可能產生干擾。該隔離級別可阻止髒讀、不可重讀和幻讀。

以上4種隔離級別和相應的副作用關係如下:

隔離級別 髒讀 不可重複讀 幻讀
未提交讀
已提交讀
可重複讀
可序列化
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章