mysql 事務級別

測試的mysql的版本號:

mysql> select version();

+-----------+
| version() |
+-----------+
| 8.0.11    |
+-----------+
1 row in set (0.02 sec)

隨便創建一個表:比如就是my_test,字段有三個,id(int),name(varchar),age(int)

CREATE TABLE `my_test` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `age` int(11) DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

 

mysql 默認的事務級別爲repeatable read (可以重複讀)

查看當前mysql全局的事務級別:

select @@global.TRANSACTION_isolation  

mysql> select @@global.TRANSACTION_isolation;

+--------------------------------+
| @@global.TRANSACTION_isolation |
+--------------------------------+
| REPEATABLE-READ                |
+--------------------------------+
1 row in set (0.00 sec)

 

修改全局的事務級別:

set GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED


關閉事務的主動提交: set global autocommit=off

 

記住global的設置後,重新開啓的終端才起作用

 

此時查看:

mysql> SET GLOBAL TRANSACTION ISOLATION LEVEL read uncommitted;
Query OK, 0 rows affected (0.00 sec)

// 記住global的設置後,重新開啓的終端才起作用,查看隔離級別
mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| READ-UNCOMMITTED        |
+-------------------------+
1 row in set (0.00 sec)

mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| READ-UNCOMMITTED        |
+-------------------------+
1 row in set (0.00 sec)

 

查看錶中的數據:

mysql> select * from my_test;

+----+----------+------+
| id | name     | age  |
+----+----------+------+
|  1 | jeffchan |   20 |
|  2 | caraliu  |   18 |
+----+----------+------+
2 rows in set (0.00 sec)

 

1、當事務級別是 READ UNCOMMITTED (有髒讀,幻讀,不可重複讀)

現在開啓mysql,然後打開兩個操作界面:   

那麼就有兩個需要自己手動提交的事務了:記錄爲A , B

兩個終端同時開啓事務,命令上面的數字爲執行的順序:

A事務:

1
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

4
mysql> update my_test set name="jeffchan1" where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

5
mysql> select * from my_test;
+----+-----------+------+
| id | name      | age  |
+----+-----------+------+
|  1 | jeffchan1 |   20 |
|  2 | caraliu   |   18 |
+----+-----------+------+
2 rows in set (0.00 sec)

=========================================================================================

B事務:

2
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

3
mysql> select * from my_test;
+----+-----------+------+
| id | name      | age  |
+----+-----------+------+
|  1 | jeffchan  |   20 |
|  2 | caraliu   |   18 |
+----+-----------+------+
2 rows in set (0.00 sec)

6
mysql> select * from my_test;
+----+-----------+------+
| id | name      | age  |
+----+-----------+------+
|  1 | jeffchan1 |   20 |
|  2 | caraliu   |   18 |
+----+-----------+------+
2 rows in set (0.00 sec)

A: 現在在事務A中修改表的記錄:update my_test set name="jeffchan1" where id = 1 

B:  此時起始事務還是沒有提交,但是現在在B事務中:select * from my_test 會發現id=1的那條記錄的name的值給改了,爲

jeffchan1,這就是所謂的髒讀(因爲有可能事務A失敗回滾了,此時事務B這個值其實時無效的,就是錯誤的值)

 

因爲讀未提交是最低級別的隔離,所以髒讀(讀取到未提交的數據)會存在(因爲這個級別是基本不用的),不可重複讀也存在,幻讀也會存在。

 

 

 2、當事務級別時: READ COMMITTED (解決了髒讀問題,幻讀和不可重複讀還是有)

set GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED   

設置完後,一定記得要重啓開啓新的終端。

A終端 :

1
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

3
mysql> select * from my_test;
+----+----------+------+
| id | name     | age  |
+----+----------+------+
|  1 | jeffchan |   20 |
|  2 | caraliu  |   18 |
+----+----------+------+
2 rows in set (0.00 sec)

mysql> update my_test set name="jeffchan2" where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

4
mysql> select * from my_test;
+----+-----------+------+
| id | name      | age  |
+----+-----------+------+
|  1 | jeffchan2 |   20 |
|  2 | caraliu   |   18 |
+----+-----------+------+
2 rows in set (0.00 sec)

6
mysql> commit;
Query OK, 0 rows affected (0.16 sec)

=========================================================================================

B終端:

2
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

5
mysql> select * from my_test;
+----+----------+------+
| id | name     | age  |
+----+----------+------+
|  1 | jeffchan |   20 |
|  2 | caraliu  |   18 |
+----+----------+------+
2 rows in set (0.00 sec)

A終端提交事務:此時查看發現修改了
6
mysql> select * from my_test;
+----+-----------+------+
| id | name      | age  |
+----+-----------+------+
|  1 | jeffchan2 |   20 |
|  2 | caraliu   |   18 |
+----+-----------+------+
2 rows in set (0.00 sec)

 

 事務A:  update my_test set name="jaychou1" where id = 2 ,不提交事務

 事務B:  select * from my_test 發現id=2的數據沒有被修改,所以已經沒有髒讀了,但是此時你將事務A提交,此時

 再進行 select * from my_test 發現id=2的數據被修改了。也是同一個事務中兩次讀的數據是不一樣的,這個叫不可以重複讀,不  可以在一個事務中重複讀某個記錄,可能會出現不一致現象),此時幻讀存在。

 

3、當事務級別時: REPEATABLE READ (解決了髒讀問題和不可重複讀問題,幻讀還是存在)

set GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ

設置完後,一定記得要重啓開啓新的終端。

 

A事務:

1
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

3
mysql> update my_test set name="jeffchan3" where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

4
mysql> select * from my_test;
+----+-----------+------+
| id | name      | age  |
+----+-----------+------+
|  1 | jeffchan3 |   20 |
|  2 | caraliu   |   18 |
|  3 | hello     |   12 |
+----+-----------+------+
3 rows in set (0.00 sec)


5
mysql> commit;
Query OK, 0 rows affected (0.16 sec)

=========================================================================================


B事務:

2
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

3
mysql> select * from my_test;
+----+-----------+------+
| id | name      | age  |
+----+-----------+------+
|  1 | jeffchan2 |   20 |
|  2 | caraliu   |   18 |
|  3 | hello     |   12 |
+----+-----------+------+
3 rows in set (0.00 sec)


6
mysql> select * from my_test;
+----+-----------+------+
| id | name      | age  |
+----+-----------+------+
|  1 | jeffchan2 |   20 |
|  2 | caraliu   |   18 |
|  3 | hello     |   12 |
+----+-----------+------+
3 rows in set (0.00 sec)

 

很明顯A事務修改(我試了下,插入和修改也是一樣的結果)記錄的時候,不管是否提交事務,B事務都不會讀到A事務中修改的記錄,所以不管B事務在事務中重複多少次讀取記錄,都是一樣的,所以叫可以重複讀,在讀取數據的層面,不會出現幻讀的情況。

但是update記錄時,不做條件限制的話,會update到別的事務新插入的其他記錄,當前事務查看時,沒看到那條記錄,其實它已經存在了,然後做範圍修改的時候,會修改到它,好像出現幻覺一樣。每一個命令上面加一個執行的順序。

 

A事務:

1
mysql> begin; 
Query OK, 0 rows affected (0.00 sec)

3
mysql> select * from my_test;
+----+-----------+------+
| id | name      | age  |
+----+-----------+------+
|  1 | jeffchan3 |   20 |
|  2 | caraliu   |   18 |
|  3 | hello     |   13 |
+----+-----------+------+
3 rows in set (0.00 sec)

6
mysql> select * from my_test;
+----+-----------+------+
| id | name      | age  |
+----+-----------+------+
|  1 | jeffchan3 |   20 |
|  2 | caraliu   |   18 |
|  3 | hello     |   13 |
+----+-----------+------+
3 rows in set (0.00 sec)

8
mysql> update my_test set age = 40;
Query OK, 4 rows affected (0.00 sec)
Rows matched: 4  Changed: 4  Warnings: 0

9
mysql> commit;
Query OK, 0 rows affected (0.08 sec)

10
mysql> select * from my_test;
+----+-----------+------+
| id | name      | age  |
+----+-----------+------+
|  1 | jeffchan3 |   40 |
|  2 | caraliu   |   40 |
|  3 | hello     |   40 |
|  4 | hi        |   40 |
+----+-----------+------+
4 rows in set (0.00 sec)

=============================================================================================

B事務:

2
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

4
mysql> select * from my_test;
+----+-----------+------+
| id | name      | age  |
+----+-----------+------+
|  1 | jeffchan3 |   20 |
|  2 | caraliu   |   18 |
|  3 | hello     |   13 |
+----+-----------+------+
3 rows in set (0.00 sec)

5
mysql> insert into my_test values(4,"hi",30);
Query OK, 1 row affected (0.00 sec)

7
mysql> commit;
Query OK, 0 rows affected (0.17 sec)


可以看到當執行到第10步的時候,查出來的結果,事務B新插入的記錄也被修改了。所以幻讀依然存在。

 

4、當事務級別時: SERIALIZABLE (不存在併發問題,但是效率很低)

set GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE

設置完後,一定記得要重啓開啓新的終端。

 

A事務:

1
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

5 這一步會阻塞
mysql> select * from my_test;

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

==========================================================================================

B事務:

2
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

3
mysql> select * from my_test;
+----+-----------+------+
| id | name      | age  |
+----+-----------+------+
|  1 | jeffchan3 |   40 |
|  2 | caraliu   |   40 |
|  3 | hello     |   40 |
|  4 | hi        |   40 |
+----+-----------+------+
4 rows in set (0.00 sec)

4
mysql> insert into my_test values(5,"good",13);
Query OK, 1 row affected (0.00 sec)

發現在第五步的時候,會阻塞查詢的指令,所以沒有併發問題,但是會很消耗性能,所以也是基本不使用的隔離級別

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章