時過一年從新拾起博文記錄,但願後面都能堅持下來。 接着以前MySql的學習,先記錄下這篇。javascript
如下都是基於mysql8 innodb存儲引擎進行分析的。 html
步驟 | 事務1 | 事務2 |
1 | 設置隔離級別java mysql> set @@session.transaction_isolation |
|
2 | 開啓事務1mysql mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> select * from t; Empty set (0.00 sec) |
|
3 |
無需管隔離級別,只開啓事務2並插入記錄
mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> insert into t select 1, '1'; Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 |
|
4 | 此時能查到事務2中未提交事務中的數據,這就是髒讀。sql mysql> select * from t; +------+------+ | id | name | +------+------+ | 1 | 1 | +------+------+ 1 row in set (0.00 sec) |
1 mysql> show variables like '%isolation%'; 2 +-----------------------+------------------+ 3 | Variable_name | Value | 4 +-----------------------+------------------+ 5 | transaction_isolation | READ-UNCOMMITTED | 6 +-----------------------+------------------+ 7 1 row in set (0.00 sec)
步驟 | 事務1 | 事務2 |
1 | 先設置隔離級別
mysql> set @@session.transaction_isolation |
|
2 | 開啓事務1,查詢t表記錄爲空
mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> select * from t; Empty set (0.00 sec) |
|
3 | 無需管隔離級別,只開啓事務2並插入記錄數據庫 mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> insert into t select 2, '2'; Query OK, 1 row affected (0.01 sec) Records: 1 Duplicates: 0 Warnings: 0 |
|
4 | 繼續查詢表t依然顯示爲空session (沒有讀取到事務2未提交的數據,因此不存在髒讀問題)併發 mysql> select * from t; Empty set (0.00 sec) |
|
5 | 提交事務2性能 mysql> commit; |
|
6 | 繼續查詢表t,此時能查詢事務2已提交的數據記錄(出現先後查詢不一致)學習 mysql> select * from t; +------+------+ | id | name | +------+------+ | 2 | 2 | +------+------+ |
步驟 | 事務1 | 事務2 |
1 | 設置隔離級別 mysql> set @@session.transaction_isolation |
|
2 | 開啓事務1,並查詢 mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> select * from t; +------+------+ | id | name | +------+------+ | 3 | 3 | +------+------+ |
|
3 | 無需管隔離級別,只開啓事務2並插入記錄 mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> insert into t select 4, '4'; Query OK, 1 row affected (0.01 sec) Records: 1 Duplicates: 0 Warnings: 0 |
|
4 | 繼續查詢表t依然只有一條記錄id=3
(沒有讀取到事務2未提交的數據,因此不存在髒讀問題) mysql> select * from t; +------+------+ | id | name | +------+------+ | 3 | 3 | +------+------+ |
|
5 |
將第二個窗口中的事務提交。
mysql> commit; |
|
6 | 繼續查詢表t依然只有一條記錄id=3
(沒有讀取到事務2已提交的數據,因此不存在不可重複讀問題) mysql> select * from t; +------+------+ | id | name | +------+------+ | 3 | 3 | +------+------+ |
|
7 |
接着插入一條4的記錄,但提示插入不了,提示主鍵衝突問題。
然而查詢卻沒有這條id=4記錄。 這就是
幻讀現象。
mysql> insert into t select 4, '4'; ERROR 1062 (23000): Duplicate entry '4' for key 'PRIMARY' mysql> select * from t; +----+------+ | id | name | +----+------+ | 3 | 3 | +----+------+ 1 row in set (0.00 sec) |
|
8 | 另外一種幻讀現象:接着上面操做,不插入記錄只更新記錄,將name 更新成 '5'後,發現有兩行受影響 | |
mysql> update t set name = '5'; Query OK, 2 rows affected (0.00 sec) Rows matched: 2 Changed: 2 Warnings: 0 mysql> select * from t; +----+------+ | id | name | +----+------+ | 3 | 5 | | 4 | 5 | +----+------+ |
步驟 | 事務1 | 事務2 |
9 | 查詢時加上間隙鎖 mysql> begin; mysql> select * from t where id > 0 for update; +----+------+ | id | name | +----+------+ | 3 | 5 | | 4 | 5 | +----+------+
|
|
10 | 插入記錄爲6的數據就會發現插入這條記錄獲取鎖超時,自動異常 insert into t select 6, '6'; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
|
一、髒讀:在一個事務中會讀取到其未提交事務的數據,此種現象也稱之爲髒讀
二、不可重複讀:一個事務能夠讀取另外一個已提交的事務,屢次讀取會形成不同的結果。這種現象也被稱爲不可重複讀
三、幻讀:基於可重複讀的基礎上查詢結果是同樣的,可是當對某些行進行更新或者插入時卻會受到影響操做不了,就造成了幻讀。
隔離級別
|
髒讀
|
不可重複讀
|
幻讀
|
讀未提交(uncommitted read)
|
可能出現
|
可能出現
|
可能出現
|
讀提交(committed read)
|
不會出現
|
可能出現
|
可能出現
|
可重複讀(Repeatable Read)
|
不會出現
|
不會出現
|
可能出現(加上間隙鎖就不會)
|
可串行化(Serializable)
|
不會出現
|
不會出現
|
不會出現
|
《MySql 技術內幕(Innodb)第二版》
https://dev.mysql.com/doc/refman/8.0/en/innodb-transaction-isolation-levels.html