mysql事務隔離的一點理解

前言

先介紹一下事務的概念
事務(Transaction)就是數據庫管理的一個邏輯單位,由一個有效的數據庫操做序列構成。mysql

事物ACID特性sql

  • 原子性(Atomicity):事務做爲一個總體被執行,要麼所有成功執行,要麼所有失敗
  • 一致性(Consistency):指的是邏輯上的一致性,即全部操做是符合現實當中的指望的
  • 隔離性(Isolation):多個事務併發時,一個事務不該該影響其餘事務的執行
  • 持久性(Durability):被提交過的事務對數據庫的修改應該永久保存在數據庫中

通俗的理解,就是將一系列的數據庫操做(增刪改查)看作一個總體,要麼全部操做都成功,要麼都失敗。數據庫

1、產生的問題

若是沒有事務隔離的話,會發生如下的問題併發

1. 髒讀

髒讀是指一個事務讀取了另外一個事務未提交的數據測試

2. 不可重複讀

不可重複讀是指事務讀取某行數據,屢次讀取的結果不一樣rest

不可重複讀和髒讀的區別:不可重複讀是事務A讀取某行數據後,事務B修改這行數據並提交以後,事務A再去讀這行數據,讀到了修改後的數據

3. 幻讀

幻讀是指事務A讀某行數據後爲100,事務B把這行數據改成99並提交,事務A查看這行數據,發現仍是以前讀取的100,但實際這行數據已是99了,這就是幻讀。
上面還有點不清晰,借鑑一下別人的白話解釋code

幻讀,並非說兩次讀取獲取的結果集不一樣,幻讀側重的方面是某一次的 select 操做獲得的結果所表徵的數據狀態沒法支撐後續的業務操做。更爲具體一些:select 某記錄是否存在,不存在,準備插入此記錄,但執行 insert 時發現此記錄已存在,沒法插入,此時就發生了幻讀。

2、事務隔離

  • Read uncommitted(讀未提交)
  • Read Committed(讀已提交)
  • Repeatable Reads(可重複讀)
  • Serializable(串行化)

1. 讀未提交

隔離級別最低的一種事務級別,會發生髒讀,不可重複讀,幻讀事務

2. 讀已提交

讀到的都是別人提交後的值。這種隔離級別下,會引起不可重複讀和幻讀,但避免了髒讀。ci

3. 可重複讀

這種隔離級別下,會引起幻讀,但避免了髒讀、不可重複讀。get

4. 串行化

最嚴格的隔離級別。在串行化隔離級別下,全部事務按照次序依次執行。髒讀、不可重複讀、幻讀都不會出現。

3、測試

下面咱們在MYSQL下,來對上面四種事務隔離進行測試
在mysql中首先創建一張student表,有以下數據

學生id 學生姓名 學生性別
1 花輪
2 小丸子

看一下mysql的默認隔離級別

mysql> SELECT @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set (0.03 sec)

默認是可重複讀,下面咱們就來測試

1. 讀未提交

首先開啓事務A,讀表中數據數據

mysql> begin;

mysql> select * from student ;
+----+------------+------+
| id | name       | sex  |
+----+------------+------+
|  1 | 花輪          | 男   |
|  2 | 小丸子        | 女   |
+----+------------+------+
2 rows in set (0.02 sec)

打開另外一個窗口,開啓事務B,修改表中數據,不提交

mysql> begin ;

mysql> update student set sex='女' where id=1;
Query OK, 0 rows affected (0.00 sec)

再回到事務A中讀表數據,看是否改變

mysql> select * from student ;
+----+------------+------+
| id | name       | sex  |
+----+------------+------+
|  1 | 花輪          | 男   |
|  2 | 小丸子        | 女   |
+----+------------+------+
2 rows in set (0.01 sec)

能夠發如今mysql下沒有發生髒讀。把上面兩個事務進行回滾(rollback)操做

2. 讀已提交

首先開啓事務A,讀表中數據數據

mysql> begin;

mysql> select * from student ;
+----+------------+------+
| id | name       | sex  |
+----+------------+------+
|  1 | 花輪          | 男   |
|  2 | 小丸子        | 女   |
+----+------------+------+
2 rows in set (0.02 sec)

打開另外一個窗口,開啓事務B,修改表中數據,並提交

mysql> begin ;

mysql> update student set sex='女' where id=1;
Query OK, 0 rows affected (0.00 sec)

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

再回到事務A中讀表數據,看是否改變

mysql> select * from student ;
+----+------------+------+
| id | name       | sex  |
+----+------------+------+
|  1 | 花輪          | 男   |
|  2 | 小丸子        | 女   |
+----+------------+------+
2 rows in set (0.00 sec)

能夠發如今mysql下避免了不可重複讀。將以前修改的數據改回來

mysql> update student set sex='男' where id=1;

3. 可重複讀

開啓A事務,讀取表中數據

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

mysql> select * from student ;
+----+------------+------+
| id | name       | sex  |
+----+------------+------+
|  1 | 花輪          | 男   |
|  2 | 小丸子        | 女   |
+----+------------+------+
2 rows in set (0.00 sec)

打開另外一個窗口,開啓事務B,插入一條數據,並提交

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

mysql> insert into student values ('3','飛飛' ,'女' );
Query OK, 1 row affected (0.01 sec)

mysql> select * from student;
+----+------------+------+
| id | name       | sex  |
+----+------------+------+
|  1 | 花輪          | 男   |
|  2 | 小丸子        | 女   |
|  3 | 飛飛       | 女   |
+----+------------+------+
3 rows in set (0.00 sec)

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

在A事務中查看數據

mysql> select * from student ;
+----+------------+------+
| id | name       | sex  |
+----+------------+------+
|  1 | 花輪          | 男   |
|  2 | 小丸子        | 女   |
+----+------------+------+
2 rows in set (0.00 sec)

能夠看出,A事務產生了幻讀,由於實際上id=3這行數據是有的。

4. 串行化

前面的測試已經證實,在mysql的REPEATABLE-READ下,事務不會串行。

補充

這裏多提一點,就是在REPEATABLE-READ下,事務是會發生死鎖的,但mysql會自動給你處理死鎖。

表student

學生id 學生姓名 學生性別
1 花輪
2 小丸子

表student1

學生id 學生姓名 學生性別
1 qq
2 ww

第一步,開啓事務A,將student表 id=1 的 sex更改成女

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

mysql> update student set sex='女' where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

第二步,開啓事務B,將student1表 id=1 的 sex更改成男

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

mysql> 
mysql> update student1 set sex='男' where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

第三步,在事務A中,將student1表中 id=1的 sex更改成女

mysql> update student1 set sex='女' where id=1;

這裏,事務A處於等待狀態,由於這個更新操做須要等到事務B處理完成才能進行,並且若是超過必定時間沒有處理,會提示超時錯誤

第四步,在事務B中,將將student1表中 id=1的 sex更改成男

mysql> update student set sex='男' where id=1;
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

能夠看到在事務B中報錯,產生了死鎖
再回去看事務A,發現第三步的更新成功了

mysql> update student1 set sex='女' where id=1;
Query OK, 0 rows affected (19.03 sec)
Rows matched: 1  Changed: 0  Warnings: 0

這裏涉及到的實際上是數據庫鎖的概念,之後有機會再寫篇有關的文章


第一次寫文章,有不少不足的地方,請多多見諒~~

相關文章
相關標籤/搜索