MySQL事務(臟讀、不可重復讀、幻讀)


1. 什么是事務?

  是數據庫操作的最小工作單元,是作為單個邏輯工作單元執行的一系列操作;這些操作作為一個整體一起向系統提交,要么都執行、要么都不執行;事務是一組不可再分割的操作集合(工作邏輯單元);

 

2.事務的四大特性ACID

  一個事務往往具有一下特性:

  原子性(ATOMICITY): 
  一個事務要被完全的無二義性的做完或撤消。在任何操作出現一個錯誤的情況下,構成事務的所有操作的效果必須被撤消,數據應被回滾到以前的狀態。 

  一致性(CONSISTENCY):   

  一個事務應該保護所有定義在數據上的不變的屬性(例如完整性約束)。在完成了一個成功的事務時,數據應處於一致的狀態。換句話說,一個事務應該把系統從一個一致-狀態轉換到另一個一致狀態。舉個例子,在關系數據庫的情況下, 一個一致的事務將保護定義在數據上的所有完整性約束。 

  隔離性(ISOLATION): 

  在同一個環境中可能有多個事務並發執行,而每個事務都應表現為獨立執行。串行的執行一系列事務的效果應該同於並發的執行它們。這要求兩件事: 

  在一個事務執行過程中,數據的中間的(可能不一致)狀態不應該被暴露給所有的其他事務。 
  兩個並發的事務應該不能操作同一項數據。數據庫管理系統通常使用鎖來實現這個特征。 

  持久性(DURABILITY): 
  一個被完成的事務的效果應該是持久的。

 

3.創建事務的SQL語法

  隱式事務:事務沒有明顯的開啟或者結束的標志,在mysql中,默認是開啟自動提交的

SHOW @@autocommit;

  

  所以針對SELECT、UPDATE、DELETE、INSERT等DQL及DML語句的執行,mysql會自動提交該事務,如果關閉就需要手動提交或者回滾來完成操作。

 

  顯式事務:與隱式事務想反,有明顯的開啟或結束標志。

SET autocommit=0
[START TRANSACTION]  # 可選的語句
[DELETE | UPDATE | INSERT | SELECT ]  # DML、DQL操作
[COMMIT | ROLLBACK];  #提交或者回滾

  

  可以看出,在事務未結束之前,操作是有效的且更改了數據實體,那么試想一下,如果這是有多個事務參與, 肯定會出現各種各樣的數據不統一的情況,這就類似多個線程在沒有鎖的情況下修改同一個全局變量。

  

  顯式事務:回滾點的使用(setpoint)

SET AUTOCOMMIT=0;
START TRANSACTION;
[DELETE | UPDATE | INSERT | SELECT];  #回滾時要執行提交的部分
SAVEPOINT a;  # 設置回滾點,且變量名為a
[DELETE | UPDATE | INSERT | SELECT];  #回滾時不執行提交的部分
ROLLBACK TO a;  # 回滾時與ROLLBACK TO搭配使用

  

  可以發現在回滾點以前的數據實體被刪除、之后的數據實體因為回滾而被撤銷操作。

  注意:在事務中使用truncate時,就算rollback也會清空整張表

 

4.多個事務在不同事務隔離級別下的並發問題

  在mysql下事務的隔離級別有四種且由低到高依次為Read uncommitted 、Read committed 、Repeatable read (默認)、Serializable ,這四個級別中的后三個級別可以逐個解決臟讀 、不可重復讀 、幻讀這幾類問題

 

  1. 臟讀的情況:對於兩個事務T1與T2,T1讀取了已經被T2更新但是還沒有提交的字段之后,若此時T2回滾,T1讀取的內容就是臨時並且無效的

  開啟兩個mysql客戶端,並創建一張測試表transaction

  

  更改默認隔離級別REPEATABLE READ為READ UNCOMMITTED

SELECT @@tx_isolation; #查詢隔離級別
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; # 更改隔離級別

  

   兩個客戶端同時開啟事務,其中一個事務做UPDATE操作,另一個事務做SELECT

  

  若此時黑色背景的客戶端進行回滾,則白色背景的客戶端讀取的數據就是臨時並且無效的。即臟讀。

  

  2. 不可重復讀: 對於兩個事務T1和T2,T1讀取了一個字段,然后T2更新了該字段並提交之后,T1再次提取同一個字段,值便不相等了。

  

  重復讀取的結果不一致的情況發生。

 

  3. 幻讀: 對於兩個事務T1、T2,T1從表中讀取數據,然后T2進行了INSERT操作並提交,當T1'再次讀取的時候,結果不一致的情況發生。

  

 

5. 不同隔離級別所解決的事務並發問題

  臟讀 不可重復讀 幻讀
READ UNCOMMITTED 1 1 1
READ COMMITTED 0 1 1
REPEATABLE READ 0 0 1
SERIALIZABLE 0 0 0

  

  READ UNCOMMITTED級別不做演示,其隔離性最低,會出現臟讀、不可重復讀、幻讀等所有情況。

  READ COMMITTED級別能夠避免臟讀,下面來進行演示:

    1.避免臟讀(一個事務讀取到另一個事務未提交的數據)

  

  

  

     2. 無法避免重復讀(一個事務讀取到另一個事務已經提交的數據)

   

  

  

  

 

  REPEATABLE READ避免不可重復讀的情況發生,下面來看演示:
    1. 避免不可重復讀(一個事務讀取到另一個事務已經提交的數據)

  

    2. 無法避免幻讀(一個事務多次查詢整表數據,由於其他事務新增(刪除)記錄造成多次查詢的記錄條數不同(一個事務讀取到另一個事務已經提交的數據))

   

   

  SERIALIZABLE避免幻讀情況,阻塞方式

  

  

  可以看出,serializable級別就類似加鎖的方式,同一時刻支持多個事務並發,但是針對DML(UPDATE\INSERT\DELETE)操作時,當前發起操作的事務會被阻塞,直到其他事務commit或者rollback才會繼續執行事務語句。可見效率十分低下。

 

  

  

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM