概要:在數據庫操作中,爲了保證併發讀取數據的正確性,一致性,提出的事務隔離級別,隔離級別越高,越能保證數據的完整性和一致性,但是對併發性能的影響也越大。
一、髒讀、不可重複讀、幻讀
-
髒讀
事務A讀取事務B尚未提交的數據,如果事務B執行回滾操作,那麼A事務讀取到的數據就是髒數據。 -
不可重複讀
在一個事務中,對同一行數據重複讀取兩次,但是卻得到了不同的結果。 -
幻讀
事 務在操作過程中進行兩次查詢,兩次查詢的數據記錄數不匹配。
二、事務的隔離級別
MySQL事務有四個級別:未提交讀(read uncommitted)、已提交讀(read committed)、可重複讀(repeatable read)、串行化(serializable)
-
默認事務隔離級別
mysql> SELECT @@tx_isolation; ERROR 2006 (HY000): MySQL server has gone away No connection. Trying to reconnect... Connection id: 138591 Current database: FA +-----------------+ | @@tx_isolation | +-----------------+ | REPEATABLE-READ | +-----------------+
-
未提交讀(read uncommitted)
在事務A中可以讀取到事務B未提交的數據,但是可能產生 髒讀, 不可重複讀 和 幻讀 。測試髒讀:
mysql> set global transaction_isolation ='READ-UNCOMMITTED'; Query OK, 0 rows affected (0.00 sec) +------------------+ | @@tx_isolation | +------------------+ | READ-UNCOMMITTED | +------------------+ 1 row in set, 1 warning (0.00 sec)
1、事務A:
mysql> START TRANSACTION; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM INFO; +----+------+------+ | ID | NAME | AGE | +----+------+------+ | 1 | lisi | 18 | +----+------+------+ 1 row in set (0.00 sec)
2、事務B
mysql> START TRANSACTION; Query OK, 0 rows affected (0.00 sec) mysql> INSERT INTO INFO(NAME, AGE) VALUES('wangwu', 12); Query OK, 1 row affected (0.00 sec)
3、事務A
mysql> SELECT * FROM INFO; +----+--------+------+ | ID | NAME | AGE | +----+--------+------+ | 1 | lisi | 18 | | 2 | wangwu | 12 | +----+--------+------+ 2 rows in set (0.00 sec)
4、事務B
mysql> ROLLBACK; Query OK, 0 rows affected (0.01 sec)
5、事務A
mysql> SELECT * FROM INFO; +----+------+------+ | ID | NAME | AGE | +----+------+------+ | 1 | lisi | 18 | +----+------+------+ 1 row in set (0.00 sec) mysql> COMMIT; Query OK, 0 rows affected (0.00 sec)
由上可知:事務B在執行完步驟2後未提交,此時事務A執行查詢,查詢到B未提交的數據,然後B因某原因回滾了數據,此時事務A讀取的兩條數據中有一條是不存在的,是髒數據。
-
已提交讀(read committed)
讀取數據的事務允許其他事務繼續訪問該行數據,但是未提交的寫事務將會禁止其他事務訪問該數據行。可以避免髒讀,但可能產生不可重複讀和幻讀測試不可重複讀:
mysql> set global transaction_isolation ='READ-COMMITTED'; Query OK, 0 rows affected (0.00 sec) mysql> SELECT @@tx_isolation; +------------------+ | @@tx_isolation | +------------------+ | READ-COMMITTED | +------------------+ 1 row in set, 1 warning (0.00 sec)
1、事務A
mysql> START TRANSACTION; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM INFO; +----+------+------+ | ID | NAME | AGE | +----+------+------+ | 1 | lisi | 18 | +----+------+------+ 1 row in set (0.00 sec)
2、事務B
mysql> START TRANSACTION; Query OK, 0 rows affected (0.00 sec) mysql> UPDATE INFO SET NAME='maliu' WHERE ID='1'; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0
3、事務A
mysql> SELECT * FROM INFO; +----+------+------+ | ID | NAME | AGE | +----+------+------+ | 1 | lisi | 18 | +----+------+------+ 1 row in set (0.00 sec)
4、事務B
mysql> COMMIT; Query OK, 0 rows affected (0.01 sec)
5、事務A
mysql> SELECT * FROM INFO; +----+-------+------+ | ID | NAME | AGE | +----+-------+------+ | 1 | maliu | 18 | +----+-------+------+ 1 row in set (0.00 sec)
由上可知:當事務B修改數據後,但未提交,此時事務A是讀取不到的,所有該隔離級別可以防止髒讀;當事務B提交事務後,此時事務A再次查詢,發現數據已經被修改,兩次讀取結果不一致,產生不可重複讀。
-
可重複讀(repeatable read)
事務A在開啓事務期間,所訪問的數據是不可修改的,可以避免不可重複讀,但是可能產生幻讀。mysql> set global transaction_isolation ='REPEATABLE-READ'; Query OK, 0 rows affected (0.00 sec) mysql> SELECT @@tx_isolation; +-----------------+ | @@tx_isolation | +-----------------+ | REPEATABLE-READ | +-----------------+ 1 row in set, 1 warning (0.00 sec)
1、事務A
mysql> START TRANSACTION; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM INFO; +----+-------+------+ | ID | NAME | AGE | +----+-------+------+ | 1 | maliu | 18 | +----+-------+------+ 1 row in set (0.00 sec)
2、事務B
mysql> UPDATE INFO SET NAME='adam' WHERE ID='1'; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> COMMIT; Query OK, 0 rows affected (0.01 sec)
3、事務A
mysql> SELECT * FROM INFO; +----+-------+------+ | ID | NAME | AGE | +----+-------+------+ | 1 | maliu | 18 | +----+-------+------+ 1 row in set (0.00 sec)
4、事務A
mysql> COMMIT; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM INFO; +----+------+------+ | ID | NAME | AGE | +----+------+------+ | 1 | adam | 18 | +----+------+------+ 1 row in set (0.00 sec)
由上可知:當事務隔離級別爲可重複讀時,在事務A未提交前,是看不到其他事務提交的數據,可以避免不可重複讀,但是可能產生幻讀。
當SQL增加FOR UPDATE時,是禁止其他事務對NAME=‘adam’的數據進行操作(新增刪除)
SELECT * FROM INFO WHERE NAME = 'adam' FOR UPDATE;
FOR UPDATE是一種行級鎖,又叫排它鎖。可以解決可重複讀級別下的幻讀現象。
-
串行化(serializable)
提供嚴格的事務隔離。它要求事務串行化執行,事務只能一個接着一個地執行,不能併發執行。可以解決髒讀,不可重複讀,幻讀現象,但大大降低了併發性。