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才會繼續執行事務語句。可見效率十分低下。