Mysql的事務隔離級別有四種,以下:
1.Read Uncommitted 它容許讀取其它事務改變但未提交的髒數據,一樣會致使不可重複讀和幻讀問題.
2.Read Committed 可避免讀取髒數據,依然會致使不可重複讀和幻讀問題.
3.REPEATABLE-READ Mysql默認隔離級別,會致使幻讀.但mysql此級別採用MVCC一致性讀,也不會產生幻讀
4.Serializable 最高隔離級別,會避免出現上面的問題.mysql
可用如下方法查看當前系統的隔離級別sql
mysql> select @@global.tx_isolation,@@tx_isolation; +-----------------------+-----------------+ | @@global.tx_isolation | @@tx_isolation | +-----------------------+-----------------+ | REPEATABLE-READ | REPEATABLE-READ | +-----------------------+-----------------+ 1 row in set (0.00 sec)
未提交讀READ-UNCOMMITTED 髒讀、不可重複讀示例:session
#session A mysql> set session transaction isolation level read uncommitted; #設置隔離級別爲未提交讀 Query OK, 0 rows affected (0.00 sec) mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> select * from inno_tbl where id=2; +----+------+ | id | name | +----+------+ | 2 | John | +----+------+ 1 row in set (0.00 sec)
#session B mysql> select @@tx_isolation; +-----------------+ | @@tx_isolation | +-----------------+ | REPEATABLE-READ | +-----------------+ 1 row in set (0.00 sec) mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> update inno_tbl set name='Jack Ma' where id=2; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0
#session A mysql> select * from inno_tbl where id=2; +----+---------+ | id | name | +----+---------+ | 2 | Jack Ma | +----+---------+ 1 row in set (0.00 sec)
此時session A讀取到了session B修改但未提交的數據,若此時session B回滾,則A讀取到的數據即是無效的,這即是「髒數據」,因爲A第一次讀取到的數據與第二次讀取到的數據不一樣,這即是「不可重複讀」;同理,或在B中插入新數據,A中此事務中也會讀取的新的數據行,這即是幻讀。
一樣的流程,將A的隔離級別改成read committed,則不會產生「髒讀」,但一樣會產生「不可重複讀」和「幻讀」code
默認隔離級別REPEATABLE-READ下:事務
#session A mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> select * from inno_tbl where id=2; +----+--------------+ | id | name | +----+--------------+ | 2 | John | +----+--------------+ 1 row in set (0.00 sec)
#session B mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> update inno_tbl set name='Lucy' where id=2; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> commit; Query OK, 0 rows affected (0.03 sec)
#session A mysql> select * from inno_tbl where id=2; +----+--------------+ | id | name | +----+--------------+ | 2 | John | +----+--------------+ 1 row in set (0.00 sec) #注意,此時沒有產生「不可重複讀」問題,但如果爲查詢加上共享鎖: mysql> select * from inno_tbl1 where id=2 lock in share mode; +----+---------+ | id | name | +----+---------+ | 2 | Lucy | +----+---------+ 1 row in set (0.00 sec)
說明:會話A中的事務讀取到id爲2的inno_tbl表中的name字段爲John,而若是此時會話B中的事務將inno_tbl中id爲2的name改成Lucy並提交,若些時A中的事務再讀取此行數據時,會發現,若是直接使用select方式查詢,讀出的數據依然是舊的數據,而加上共享鎖,會讀出真正的數據.Why?由於在innodb引擎中,mysql的增刪改查語句能夠分爲兩種,一種是快照讀,一種是當前讀,只有普通的查詢語句爲快照讀,而剩餘的增刪改和加上lock in share mode共享鎖或加上for update排它鎖的查詢語句,都屬於當前讀;當時讀讀取的是最新的數據,而快照讀讀取的不必定是最新的數據.由此可推出:當在session A中以條件爲name=John來更新或刪除時,確定不會更新或刪除成功,以下所示:it
mysql> update inno_tbl set name='張三' where name='John'; Query OK, 0 rows affected (0.00 sec) Rows matched: 0 Changed: 0 Warnings: 0 mysql> delete from inno_tbl where name='John'; Query OK, 0 rows affected (0.00 sec)
若是把隔離級別改爲Read Commited, 則A會話中的查詢語句不用加lock in share mode 或for update即可查詢出B會話中已經更改提交的最新內容. 這種狀況叫作不可重複讀, 寫到這裏, 我有個小疑問, 是否是不可重複讀和幻讀是否是互相矛盾呢? 20181209答:不是, 不可重複讀主要針對修改, 幻讀主要針對插入和刪除.io