**提到事務,我們都了解事務具有4個基本屬性ACID,而通常我們不知道四個屬性的實現,這里我們嘗試對數據庫的事務進行分析,嘗試理解事務的實現。**
**事務是并發控制的基本單位**。
*****
ACID四大特性是事務實現的基礎,了解了ACID的實現,我們就清楚了事務的實現。
# 原子性
原子性保證了一組操作由多個多個子操作組成,這些子操作要么全部執行,要么全部不執行。

## 日志回滾
為了實現原子性,在寫入操作發生異常的時候,對前面已執行的更新操作進行**回滾**。
在MySQL中通過 **回滾日志(undo log)** 來實現。事務中所有的修改操作會先記錄到這個回滾日志中,然后寫入數據庫中。
比如插入數據時,回滾日志中記錄了insert into user (id) values (1);
回滾數據時需要執行 delete from user where id = 1;
回滾日志時實現了持久性。
## 事務的狀態
事務的狀態只有3中,分別是:Active,Commited,Failed

# 持久性
事務的持久性體現在:只要事務被提交,數據一定保存到數據庫中(磁盤)。
## 重做日志
MySQL通過 **重做日志(redo log)** 來實現事務的持久性。重做日志由兩部分組成,分別是內存中的重做日志緩沖區,磁盤中的重做日志文件。
修改數據時的寫入順序如下
1. 從磁盤讀取行記錄寫入內存
2. 內存中的行記錄被更新
3. 更新日志寫入重做日志緩沖區
4. 重做日志緩沖區的內容寫入到重做日志文件
5. 內存中的行記錄更新到磁盤
> 第4,5步在事務 commit 時執行。
重做日志以512字節的塊形式保存,跟磁盤扇區大小一致,保證了重做日志寫入磁盤的原子性。

## 原子性和一致性
回滾日志保證了發生錯誤或者需要回滾的事務能夠被成功回滾。
重做日志保證了對于已提交事務的修改能夠寫入數據庫,發生意外宕機時,從重寫日志恢復磁盤數據。
# 隔離性
> 用來描述多個事務之間的關系。
**事務并行**產生了臟讀,不可重復讀,幻讀問題。
隔離性是以上問題的解決方案。隔離性決定了一個事務里的修改,哪些內容在其他事務里是可見的。
隔離級別是隔離性的具體實現策略,分別是:
1. read uncommited (臟讀)
2. read commited (解決了“臟讀“,存在“不可重復讀“)
3. repeatable read (解決了“不可重復讀“,產生了“幻讀“)
4. serializable

## 臟讀
> 在一個事務中,讀取了其他事務未提交的數據
當隔離級別是read uncommited時,session 2 中插入的未提交數據,在session1中可以被訪問

## 不可重復讀
> 在同一個事務中,一行記錄的兩次查詢結果不一致
當隔離級別是read commited的情況下,session1中前后兩次查詢的結果不一致。
不可重復讀發生的原因是,存儲引擎不會在查詢數據時添加行鎖,鎖定id=3這條記錄。

## 幻讀
> 在同一個事務中,讀取了指定范圍的數據集之后,另一個事務往該范圍內插入了新數據
由于repeatable read的原因,session1中的兩次查詢得到了同樣的結果,但是插入數據時返回錯誤

## 隔離性(隔離級別)的實現
隔離級別是對隔離性的實現,限制同一時刻對共享資源的操作。
隔離級別的實現方式有
1. 共享鎖 & 互斥鎖
2. 多版本控制,支持數據被事務更新時對舊版本數據的訪問,顯著提高了讀性能。
## Next-Key解決幻讀問題

當我們更新索引列age時,比如 `SELECT * FROM users WHERE age = 25 FOR UPDATE;`,InnoDB不僅鎖定了 (21,25] 區間,還鎖定了 (25, 30] 區間。確保其他事務無法插入age=25的數據。
## 多版本并發控制
為了提升了“重復讀“的讀性能。
InnoDB維護了一個版本號,每啟動一個事務,版本號就加一。表中添加兩列,表示“創建時間“和“過期時間“,用來保存版本號。
CURD操作對這兩列的維護策略如下
* insert:寫入創建時間
* update:更新創建時間,寫入過期時間
* select:創建時間小于等于當前事務的版本號
* delete:寫入過期時間
## 小結
隔離級別“提交讀“解決了“臟讀“問題
隔離級別“重復讀“解決了“不可重復讀“問題
隔離級別“串行化“解決了“幻讀“問題
但由于“串行化“的性能問題,innodb通過Next-key來解決幻讀問題。
多版本并發控制提升了“重復讀“讀性能
## 參考資料
[『淺入深出』MySQL 中事務的實現](https://draveness.me/mysql-transaction)
[淺談數據庫并發控制 - 鎖和 MVCC](https://draveness.me/database-concurrency-control)