PostgreSQL資料庫事務實現方法分析
本文例項講述了PostgreSQL資料庫事務實現方法。分享給大家供大家參考,具體如下:
事務簡介
- 事務管理器:有限狀態機
- 日誌管理器
- CLOG:事務的執行結果
- XLOG:undo/redo日誌
- 鎖管理器:實現併發控制,讀階段採用MVCC,寫階段採用鎖控制實現不同的隔離級別
- 日誌管理器
事務是所有資料庫系統的一個基本概念。 一次事務的要點就是它把多個步驟捆綁成了一個單一的,不成功則成仁的操作。 其它併發的事務是看不到在這些步驟之間的中間狀態的,並且如果發生了一些問題, 導致該事務無法完成,那麼所有這些步驟都完全不會影響資料庫。PostgreSQL為每條事務建立一個postgre程序,併發執行事務。採用分層的機制執行事務,上層事務塊和底層事務。上層事務塊是使用者眼中的事務,用於控制事務執行的狀態;底層事務是事務中的每條語句,可以改變上層事務塊的狀態。
上層事務塊
每個postgre程序只有一個事務塊,上層事務塊記錄著本次事務執行過程中的各個狀態。
typedef enum TBlockState { /* not-in-transaction-block states */ TBLOCK_DEFAULT,/* idle */ TBLOCK_STARTED,/* 執行簡單查詢事務 */ /* transaction block states */ TBLOCK_BEGIN,/* 遇見事務開始BEGIN */ TBLOCK_INPROGRESS,/* 事務正在執行中 */ TBLOCK_PARALLEL_INPROGRESS,/* live transaction inside parallel worker */ TBLOCK_END,/* 遇見事務結束COMMIT/END的時候設定 */ TBLOCK_ABORT,/* 事務出錯,等待ROLLBACK */ TBLOCK_ABORT_END,/* 事務出錯,收到ROLLBACK */ TBLOCK_ABORT_PENDING,/* 事務處理中,接收到ROLLBACK */ TBLOCK_PREPARE,/* 事務處理中,收到PREPARE(分散式事務) */ /* subtransaction states */ TBLOCK_SUBBEGIN,/* starting a subtransaction */ TBLOCK_SUBINPROGRESS,/* live subtransaction */ TBLOCK_SUBRELEASE,/* RELEASE received */ TBLOCK_SUBCOMMIT,/* COMMIT received while TBLOCK_SUBINPROGRESS */ TBLOCK_SUBABORT,/* failed subxact,awaiting ROLLBACK */ TBLOCK_SUBABORT_END,ROLLBACK received */ TBLOCK_SUBABORT_PENDING,/* live subxact,ROLLBACK received */ TBLOCK_SUBRESTART,ROLLBACK TO received */ TBLOCK_SUBABORT_RESTART /* failed subxact,ROLLBACK TO received */ } TBlockState;
常見的事務塊狀態轉換圖
- startTransactionCommand:事務塊中每條語句執行前都會呼叫。
- commitTransactionCommand:事務塊中每條語句執行結束都會呼叫
- abortCurrentTransaction:事務塊中語句執行錯誤,在呼叫點呼叫
- BeginTransactionBlock:遇見BEGIN命令呼叫,狀態變為TBLOCK_BEGIN
- EndTransactionBlock:遇見END呼叫,可能成功提交,也可能回滾
- AbortTransactionBlock:遇見ABORT指令呼叫
底層事務
底層事務是需要執行的每條命令,負責處理資源和鎖的獲取和釋放,訊號的處理,日誌記錄等等
typedef enum TransState { TRANS_DEFAULT,/* idle */ TRANS_START,/* transaction starting */ TRANS_INPROGRESS,/* inside a valid transaction */ TRANS_COMMIT,/* commit in progress */ TRANS_ABORT,/* abort in progress */ TRANS_PREPARE /* prepare in progress */ } TransState;
主要有四個函式:
- StartTransaction:由BEGIN的startTransactionCommand呼叫,呼叫結束後事務塊狀態為TBLOCK_STARTED
- CommitTransaction:由END的commitTransactionCommand呼叫,提交事務
- AbortTransaction和CleanupTransaction:釋放資源,恢復預設狀態
分散式事務
PostgreSQL提供了分散式事務中的,兩階段提交的介面
併發控制
PostgreSQL採用MVCC的方式進行併發控制,每個事務看到的是一段時間前的資料快照。同時,MVCC並不能夠解決所有問題,所以也提供了行級和表級的鎖。
標準的事務隔離級別有4個,而PostgreSQL只實現了讀已提交和可序列化。
鎖
PostgreSQL實現了8種鎖(可怕)
太多了,就記住幾個吧。
- 行共享鎖:select for update/for share
- 表共享鎖:select
- 行排他鎖:insert/update/delete
- 表排他鎖:drop
加鎖的物件
- 表
- 表鎖
- 會話鎖
- 擴充套件鎖:新增表空間
- 頁:對索引頁面
- 元組:
- 事務:
死鎖處理
- postgresql檢測出最後一個等待的殺掉,oracle是第一個等待的殺掉
- 死鎖檢測演算法(等待圖)
MVCC
關鍵詞:
- 基於事務ID
- 行級多版本
- 無回滾段,行記憶體儲
- 一次UPDATE,產生記錄兩個版本
- 兩個版本都存在頁面內部
typedef struct HeapTupleFields { TransactionId t_xmin; /* Insert,Update事務 */ TransactionId t_xmax; /* Delete,Update,Row Locks事務ID */ union { CommandId t_cid; /* 操作ID */ TransactionId t_xvac; /* old-style VACUUM FULL xact ID */ } t_field3; } HeapTupleFields;
cmin
:插入該元組的命令在插入事務中的命令標識(從0開始累加)
cmax
:刪除該元組的命令在插入事務中的命令標識(從0開始累加)
ctid
:相當於rowid , <資料塊ID,偏移量>
XID
:事務ID
Xid_snapshot
:當前系統中未提交的事務
CLOG
:事務狀態日誌(已提交的日誌)
隔離級別
- RC:讀已提交
- 兩個事務可以併發更新同一行
- 一個事務更新,一個事務刪除同一行,刪除操作會上鎖
- RR:讀未提交,其實是snapshot isolation,(衝突狀態會回滾)
- 可序列化:serialize snapshot isolation,比標準可序列化要高,通過加記憶體中的意向鎖實現,不允許預加鎖的資料被其他事務變更
資料可見性判斷
- 記錄的頭部XID資訊比當前事務更早(rr和ssi有這個要求,read commited沒有這個要求,讀已經提交可以讀未來的事務!!)
- 記錄頭部的XID資訊不在當前的XID_snapshot中,(記錄上的事務狀態不是未提交的事務)
- 記錄頭部的XID資訊在CLOG中代表已提交。
- MVCC需要判斷該行資料在這個事務中的有效性,可見性,可更新性(需要鎖的幫助才能正確執行隔離級別)
- 判斷條件:若xmin等於當前事務ID,則包含所有xmax=0(未被刪除)的元組。
若與xmin相等的事務ID對應的事務已經被提交,則包含所有xmax=0或xmax為當前事務ID的元組。 - 實現概要
- 對讀不用加鎖,對寫加鎖(只阻塞寫),事務結束對比是否衝突
多行資料需要過期版本回收
- 頁面級:頁面訪問時回收
- 表級/系統級: autovacuum; vacuum
日誌
- pg_log:資料庫活動日誌(也就是資料庫的操作日誌);
- pg_xlog:事務日誌,記錄事務的執行過程,redo日誌
- pg_clog:事務狀態日誌(pg_clog是pg_xlog的輔助日誌),記錄事務的結果。
希望本文所述對大家PostgreSQL資料庫程式設計有所幫助。