MySQL技術內幕InnoDB儲存引擎(七)——事務
什麼是資料庫的事務?
事務是訪問並更新資料庫中各種資料的一個程式執行單元。事務也是資料庫區別於檔案系統的一個重要特性。
事務需要滿足的特性
1.原子性
原子性就是指資料庫中的一個完整的事務是不可分割的工作單位。要麼都成功,要麼都失敗,不能執行一部分。
2.一致性
一致性指事務將資料庫從一種狀態轉變為下一種一致的狀態。
所謂一致性狀態,就是資料庫的資料滿足約束的要求。
3.隔離性
事務的隔離性要求每個讀寫事務的物件對其他事務的操作物件能相互分離,也就是一個事務提交對其他事務不可見,可以用鎖來實現。
4.永續性
永續性就是事務提交後的結果是永久的,如果傳送宕機,也能將資料進行恢復。
永續性保證事務系統的高可靠性,而不是高可用性。高可靠性
事務的分類
1.扁平事務
所有操作都處於同一層次,而且操作是原子的,要麼都執行,要麼都回滾。
特點:
- 是事務型別最簡單的一種,也是實際生產環境中最頻繁的事務。
- 不能提交或者回滾事務的某一個部分,或者幾個步驟提交。
2.帶有儲存點的扁平事務
和扁平事務的不同點就是允許事務在執行過程中回滾到該事務之前的一個狀態點。
儲存點:用來通知系統應該記住事務當前的狀態,以便之後能夠回到儲存點時的狀態。一個事務中可以有很多個儲存點。
3.鏈事務
是儲存點模式的一種變種。將事務切分為多個串聯的事務,當前事務提交之後,將處理的上下文再傳給下一個事務,像一個鏈條一樣,一環接一環。
目的: 為了解決儲存點事務中,如果發生系統崩潰,儲存點都消失的情況。這裡將儲存點都換成了事務提交,相當於在儲存點就將事務提交了,這樣就算宕機了,提交了的事務也不會損失。
問題: 鏈事務的回滾就只能在當前事務中了。所以需要將每個事務中的操作都減少一些。
4.巢狀事務
是一個層次結構框架,由一個頂層事務控制著各個層次的事務。
特點:
- 巢狀事務是由若干事務組成的一棵樹,子樹既可以是巢狀事務,也可以是扁平事務。
- 葉節點的事務是扁平事務。
- 在根節點的事務是頂層事務,其他事務都是子事務。
- 子事務可以提交也可以回滾,但是提交操作不會馬上生效,要等到頂層事務提交才會真正提交。
- 任一事務的回滾都會引起其兒子的回滾。
5.分散式事務
在一個分散式環境下執行的扁平事務,因此需要根據資料所在位置訪問網路中的不同節點。
事務的具體實現
在InnoDB上各個事務級別有其具體的實現方式:
- 鎖:隔離性。
- redo log:原子性和永續性。
- undo long:一致性。
1. redo
什麼是重做日誌?
重做日誌用來實現事務的永續性,也就是將產生一些資料庫操作儲存到日誌。這些操作的特點是,其操作結果緩衝區中,並沒有寫到磁碟中。
重做日誌的特點:
- 當觸發事務提交時就需要先將該事務的所有日誌寫到重做日誌中進行持久化。
- 重做日誌是順序寫的。
如何確保重做日誌的永續性?
為了確保每次日誌都寫入重做日誌檔案(磁碟),在每次將重做日誌緩衝寫入磁碟後,儲存引擎都需要呼叫一次fsync操作(將記憶體資料寫到磁碟)。所以,磁碟的效能決定了資料庫的效能。
如何通過重做日誌提高資料庫效能?
使用者可以設定重非永續性的情況發生。當事務提交的時候,不馬上寫入磁碟,而是等一個時間週期之後再執行fsync。這樣可以優化日誌的寫入時間,從而提高資料庫的效能。但是如果發生宕機,會丟失一部分未重新整理的資料。
重做日誌的儲存方式
InnoDB的儲存引擎中,重做日誌快取和重做日誌檔案以重做日誌塊的形式程序儲存,一個塊的大小為512位元組。如果一個頁的重做日誌大於一個塊能夠儲存的範圍,則會被分割為多個塊進行儲存。
為什麼是512位元組呢? 因為磁碟的一個扇區大小512位元組,可以保證原子性。
重做日誌緩衝寫到磁碟的觸發條件:
- 事務提交時;
- 當日志緩衝的一半空間被使用;
- log checkpoint時。
重做日誌恢復資料的原理:
- 不管上次資料庫是否正常關閉,都會嘗試進行恢復操作。
- checkpoint表示已經重新整理到磁碟的日誌序列號,所以,只需要恢復checkpoint之後的日誌序列號的日誌部分即可。
- 執行重做日誌。
2.binlog
binlog也就是二進位制檔案,是資料庫上層對已提交了的事務的SQL語句的記錄。
binlog和redo log的區別:
- 二者表面上看都是記錄了資料庫操作的日誌,但是本質上有著很大的不同。
- 重做日誌是儲存引擎層產生的,二進位制日誌是資料庫的上層產生的。二進位制日誌不僅僅正對引擎層,資料庫中任何的更改操作都會產生二進位制日誌。
- 兩種日誌記錄的內容形式不同。二進位制檔案是操作邏輯上的,重做日誌是物理格式上的。二進位制檔案對應SQL語句,而重做日誌對應引擎對資料頁得修改。
- 寫入磁碟的時間點不同。二進位制日誌只在事務提交完成後進行一次寫入,而InnoDB儲存引擎的重做日誌會不斷地寫入,不隨事務提交的順序影響。
3. undo
什麼是undo日誌?
用於事務的回滾操作。undo日誌中記錄了資料之前的版本,當執行回滾操作的時候,利用這些之前的資料資訊即可修改到之前的樣子。undo日誌也用於版本控制(MVCC),當用戶讀取一行記錄的時候,該記錄已經被其他事務佔用了,當前事務就可以根據事務隔離級別,讀取過去相應版本的資料,實現非鎖定讀,提高併發效能。
undo日誌會產生重做日誌,因為undo日誌也需要持久化。
undo日誌的儲存方式:
同樣採用段的方式進行儲存,每個回滾段中記錄1024個undo日誌段,而在每個undo日誌段中進行undo頁的申請。也就是undo日誌是寫入到undo日誌段中的undo頁。多個事務可以共享一個undo頁。
4.purge
用於完成最終的delete和update操作。
當delete操作和update操作提交後,只是將相應記錄的flag置為1,並沒有刪除或者修改記錄,真正的操作會延時到purge操作來完成。
為什麼需要這樣設計,而不是直接操作?
當事務提交時,其他事務可能正在引用這行,如果直接刪除會產生錯誤,所以,能不能刪除,就需要purge操作進行判斷。如果該技術已經不被其他事務引用,就可以進行真正的刪除操作。這就優點像JVM垃圾回收判斷機制。
5.group commit
什麼是group commit?
顧名思義,就是寫一堆資料到磁碟。每次事務提交都需要進行fsync操作,這樣不能利用磁碟的效率,如果每次寫入一組提交的資料,並進行寫優化,減少磁碟IO次數,就能提高效能。
MySQL實現批量二進位制日誌提交的流程:
資料
- Flush階段,將每個事務的二進位制日誌寫入記憶體;
- Sync階段,將記憶體中二進位制檔案寫入磁碟,如果有多個事務,那麼一次fsync操作就能完成日誌寫入;
- Cmmit階段,隊頭事務根據順序呼叫引擎層事務的提交。
事務的隔離級別
SQL標準定義的四個隔離級別:
- 讀未提交:會髒讀。
- 讀已提交:會不可重複讀。
- 可重複讀:會幻讀。
- 序列化:都不會
InnoDB事務隔離級別的特點: InnoDB的預設隔離級別是可重複讀,其預設事務隔離級別是可重複讀。它的可重複度級別下,通過Next-Key演算法,避免了幻讀。所以,InnoDB的可重複度就已經達到了序列化的隔離性要求。
分散式事務
什麼是分散式事務?
是指允許多個獨立的事務資源參與到一個全域性的事務當中。
InnoDB提供了對XA事務的支援,並通過XA事務來支援分散式事務的實現。必須將隔離級別設定為序列化,才能使用分散式事務。
XA事務的實現原理
XA事務由一個或者多個資源管理、一個事務管理器和一個應用程式組成:
- 資源管理器:提供訪問事務資源的方法。也就是資料庫
- 事務管理器:協調參與全域性事務的各個事務。就是連結資料庫的客戶端。
- 應用程式:定義事務的邊界,指定全域性事務中的操作。
分散式事務兩段式提交方式
- 第一階段,所有餐具全域性事務的節點開始準備,告訴事務管理器它們準備好提交了。
- 第二階段,事務管理器告訴資源管理器執行回滾還是提交。如果任何一個節點不能提交,其他節點都需要回滾。
不好的事務習慣
1.在迴圈中提交
如果在迴圈中提交,那麼迴圈很大,就需要提交很多次,每次提交都要重做日誌,這樣就會大大增加開銷。如果在迴圈最後提交,則只需要寫一個重做日誌,降低開銷。
InnoDB儲存引擎會預設自動提交。
2.使用自動提交
開發人員不能很好的掌控事務。應該把事務的控制權交給開發人員。
3.使用自動回滾
如果InnoDB在儲存過程中發生錯誤會自動執行回滾操作。
使用自動回滾無法張掌控準確資訊。
長事務
長事務就是執行時間較長的事務。
長事務一旦執行失敗,就需要回滾,會造成很大的損失,所以,需要將其切分為很多給小事務。