簡單來說,事務就是要保證一組資料庫操作,要不全部成功,要不全部失敗,在 MySQL 中,事務支援是在儲存引擎層面的,比如 MySQL 的原生 MyISAM 儲存引擎就不支援事務,這也是 MyISAM 被 InnoDB 取代的重要原因。
一、隔離性
事務的隔離性,就是我們常說的 ICAD(Atomicity,Consistency,Isolation,Durability,即原子性
,一致性
,隔離性
,永續性
)
- 原子性:事務的最小單位,保證 MySQL 的一組資料庫操作,要不全部成功要不全部失敗
- 一致性:執行事物前後,資料資源保持一致,比如轉賬,無論轉賬是否成功,轉賬者和收款者的總額應該是不變的。
- 隔離性:併發訪問資料庫時,不同事物之間的資料應該是隔離的
- 永續性:一個事物被提交後,他對資料庫的資料的改變是持久的,即使資料庫發生故障資料也不會變化
當資料庫上有多個事務同時執行的時候,就可以出現髒讀
,不可重複讀
,幻讀
的問題
- 髒讀:A 事務中,讀取到 B 事務中修改但未提交的資料,之後 B 事務回滾,導致 A 事務讀取到的是一個不存在的資料,即髒資料
- 不可重複讀:A 事務中讀取欄位 name=lisi,此時 B 事務修改 name=zhangsan 並提交,之後 A 在事務中再次讀取 name=zhangsan,這就導致 A 在同一個事務中兩次讀取到的資料不一致
- 幻讀:幻讀跟不可重複讀有點像,不過不可重複讀針對的同一條記錄不可重複讀取,幻讀指的是 A 事務讀取 name=lisi 有四條記錄,此時 B 事務刪除了一條 name=lisi 的記錄,之後 A 再次去讀 name=lisi 只能讀取到三條記錄了,幻讀針對的是記錄的數量,可以看作是不可重複讀的特例
為了解決以上問題,就有了隔離級別的概念
二、隔離級別
再說隔離級別之前,我們應該知道,隔離的越嚴格,效率就最低
,因此我們很多時候,需要在隔離級別和效率之間尋找一個平衡點
SQL 標準的事務隔離級別包括:讀未提交(read uncommitted)
,讀已提交(read committed)
,可重複讀(repeatable read)
,序列化(serializable)
- 讀未提交:一個事務還沒提交時,它做的變更就能夠被其他事務看到
- 讀已提交:一個事務提交後,它做的變更才能被其他事務看到
- 可重複讀:一個事務執行過程中看到的資料,總跟這個事務在啟動時看到的資料是一致的,當然在可重複讀隔離級別下,未提交變更對其他事務也是不可見的
- 序列化;對於同一行記錄,寫會加寫鎖,讀會加讀鎖,當出現讀寫鎖衝突的時候,後訪問的事務必須等前一個事務執行完成,才能繼續執行
三、案例
mysql> create table T(c int) engine=InnoDB;
insert into T(c) values(1);
我們來看看在不同的隔離級別下,事務 A 查到的 V1,V2,V3 分別是什麼值
- 讀未提交:A 事務能夠讀取到 B 事務更改未提交的資料,所以 V1=2,V2=2,V3=2
- 讀已提交:A 事務只能讀取到 B 事務提交後的資料,所以 V1=1,V2=2,V3=2
- 可重複讀:在 A 事務開啟後,讀取到的資料都是一樣的,所以 A 事務開始的時候值是 1,所以 V1=1,V2=1,V3=2
- 序列化:在事務 B 將 1 改成 2 的時候,會被鎖住,直到 A 事務提交後,事務 B 才能繼續執行,所以從 A 的角度來看,V1=1,V2=1,V3=2
在實現上,資料庫裡面會建立一個檢視,訪問的時候以檢視的邏輯結果為準
- 在
可重複讀隔離級別下,這個事務是事務啟動時建立的
,整個事務存在期間都用整個檢視 - 在
讀已提交隔離級別下,整個檢視是在 SQL 語句開始執行的時候建立的
- 這裡值得注意的是,
讀未提交隔離級別下直接返回記錄上的最新值
,沒有檢視概念 - 序列化隔離級別則是透過直接加鎖的方式來避免並行訪問
四、總結
在不同的隔離級別下,資料庫行為是不同的,Oracle資料庫預設隔離級別是讀已提交
,MySQL預設隔離級別是可重複讀
,如果存在 Oracle 遷移到 MySQL,為保證資料庫隔離級別一致,需要將 MySQL 的隔離級別改成讀已提交
MySQL 配置的方式是,將啟動引數transaction-isolation
的值設定成READ-COMMITTED
,可以使用show variables like 'transaction_isolation';
來檢視當前隔離級別
正常情況下,為了保證效率,我們一般都會把事務隔離級別調整成讀已提交
,那麼什麼時候需要可重複讀的場景呢
?大多數在做資料校對
的時候,不希望有其他事務來干擾資料,啟動可重複讀是很方便的
我是一零貳肆,一個關注Java技術和記錄生活的博主。
歡迎掃碼關注“一零貳肆”的公眾號,一起學習,共同進步,多看路,少踩坑。