先介紹一下事務的概念事務(Transaction)
就是數據庫管理的一個邏輯單位,由一個有效的數據庫操做序列構成。mysql
事物ACID特性
sql
通俗的理解,就是將一系列的數據庫操做(增刪改查)看作一個總體,要麼全部操做都成功,要麼都失敗。數據庫
若是沒有事務隔離的話,會發生如下的問題併發
髒讀
是指一個事務讀取了另外一個事務未提交的數據測試
不可重複讀
是指事務讀取某行數據,屢次讀取的結果不一樣rest
不可重複讀和髒讀的區別:不可重複讀是事務A讀取某行數據後,事務B修改這行數據並提交以後,事務A再去讀這行數據,讀到了修改後的數據
幻讀
是指事務A讀某行數據後爲100,事務B把這行數據改成99並提交,事務A查看這行數據,發現仍是以前讀取的100,但實際這行數據已是99了,這就是幻讀。
上面還有點不清晰,借鑑一下別人的白話解釋code
幻讀,並非說兩次讀取獲取的結果集不一樣,幻讀側重的方面是某一次的 select 操做獲得的結果所表徵的數據狀態沒法支撐後續的業務操做。更爲具體一些:select 某記錄是否存在,不存在,準備插入此記錄,但執行 insert 時發現此記錄已存在,沒法插入,此時就發生了幻讀。
隔離級別最低的一種事務級別,會發生髒讀,不可重複讀,幻讀事務
讀到的都是別人提交後的值。這種隔離級別下,會引起不可重複讀和幻讀,但避免了髒讀。ci
這種隔離級別下,會引起幻讀,但避免了髒讀、不可重複讀。get
最嚴格的隔離級別。在串行化隔離級別下,全部事務按照次序依次執行。髒讀、不可重複讀、幻讀都不會出現。
下面咱們在MYSQL下,來對上面四種事務隔離進行測試
在mysql中首先創建一張student表,有以下數據
學生id | 學生姓名 | 學生性別 |
---|---|---|
1 | 花輪 | 男 |
2 | 小丸子 | 女 |
看一下mysql的默認隔離級別
mysql> SELECT @@tx_isolation; +-----------------+ | @@tx_isolation | +-----------------+ | REPEATABLE-READ | +-----------------+ 1 row in set (0.03 sec)
默認是可重複讀,下面咱們就來測試
首先開啓事務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)操做
首先開啓事務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;
開啓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這行數據是有的。
前面的測試已經證實,在mysql的REPEATABLE-READ
下,事務不會串行。
這裏多提一點,就是在REPEATABLE-READ
下,事務是會發生死鎖的,但mysql會自動給你處理死鎖。
表student
學生id | 學生姓名 | 學生性別 |
---|---|---|
1 | 花輪 | 男 |
2 | 小丸子 | 女 |
表student1
學生id | 學生姓名 | 學生性別 |
---|---|---|
1 | 女 | |
2 | ww | 男 |
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
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
mysql> update student1 set sex='女' where id=1;
這裏,事務A處於等待狀態,由於這個更新操做須要等到事務B處理完成才能進行,並且若是超過必定時間沒有處理,會提示超時錯誤
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
這裏涉及到的實際上是數據庫鎖的概念,之後有機會再寫篇有關的文章
第一次寫文章,有不少不足的地方,請多多見諒~~