您好,登錄后才能下訂單哦!
本篇內容介紹了“怎么理解PostgreSQL事務管理”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
README
src/backend/access/transam/README The Transaction System ====================== 事務系統 PostgreSQL's transaction system is a three-layer system. The bottom layer implements low-level transactions and subtransactions, on top of which rests the mainloop's control code, which in turn implements user-visible transactions and savepoints. PostgreSQL的事務分為3層,底層實現了低層次的事務和子事務,在其頂上駐留主循環控制代碼, 而主循環實現了用戶可見性事務和保存點. The middle layer of code is called by postgres.c before and after the processing of each query, or after detecting an error: StartTransactionCommand CommitTransactionCommand AbortCurrentTransaction Meanwhile, the user can alter the system's state by issuing the SQL commands BEGIN, COMMIT, ROLLBACK, SAVEPOINT, ROLLBACK TO or RELEASE. The traffic cop redirects these calls to the toplevel routines BeginTransactionBlock EndTransactionBlock UserAbortTransactionBlock DefineSavepoint RollbackToSavepoint ReleaseSavepoint respectively. Depending on the current state of the system, these functions call low level functions to activate the real transaction system: StartTransaction CommitTransaction AbortTransaction CleanupTransaction StartSubTransaction CommitSubTransaction AbortSubTransaction CleanupSubTransaction 在處理查詢的前后或者檢測到錯誤時,postgres.c會調用中間層的代碼: StartTransactionCommand CommitTransactionCommand AbortCurrentTransaction 在此期間,通過執行BEGIN/COMMIT/ROLLBACK/SAVEPOINT/ROLLBACK TO/RELEASE命令改變系統狀態. 調度程序會把這些調用重定向至相應的頂層例程上. BeginTransactionBlock EndTransactionBlock UserAbortTransactionBlock DefineSavepoint RollbackToSavepoint ReleaseSavepoint 依賴于當前的系統狀態,這些函數調用底層函數激活真正的事務系統: StartTransaction CommitTransaction AbortTransaction CleanupTransaction StartSubTransaction CommitSubTransaction AbortSubTransaction CleanupSubTransaction Additionally, within a transaction, CommandCounterIncrement is called to increment the command counter, which allows future commands to "see" the effects of previous commands within the same transaction. Note that this is done automatically by CommitTransactionCommand after each query inside a transaction block, but some utility functions also do it internally to allow some operations (usually in the system catalogs) to be seen by future operations in the same utility command. (For example, in DefineRelation it is done after creating the heap so the pg_class row is visible, to be able to lock it.) 另外,在事務內,調用CommandCounterIncrement增加命令計數,這可以讓未來的命令可以看到 在同一個事務中先前命令的影響. 注意該動作由CommitTransactionCommand在事務塊內部完成每個查詢后自動完成, 但某些工具函數同樣會內部實現此功能以允許某些操作(通常在系統目錄中)可被未來同樣的工具命令看到. (比如,在DefineRelation,在創建堆后已完成,因此pg_class中的行已可見,并能執行鎖定) For example, consider the following sequence of user commands: 舉個例子,考慮下面一組用戶命令: 1) BEGIN 2) SELECT * FROM foo 3) INSERT INTO foo VALUES (...) 4) COMMIT In the main processing loop, this results in the following function call sequence: 在主處理循環,會形成下面函數調用序列: / StartTransactionCommand; -- middle / StartTransaction; -- bottom 1) < ProcessUtility; << BEGIN \ BeginTransactionBlock; -- top \ CommitTransactionCommand; -- middle / StartTransactionCommand; -- middle 2) / PortalRunSelect; << SELECT ... \ CommitTransactionCommand; -- middle \ CommandCounterIncrement; / StartTransactionCommand; -- middle 3) / ProcessQuery; << INSERT ... \ CommitTransactionCommand; -- middle \ CommandCounterIncrement; / StartTransactionCommand; -- middle / ProcessUtility; << COMMIT 4) < EndTransactionBlock; -- top \ CommitTransactionCommand; -- middle \ CommitTransaction; -- bottom The point of this example is to demonstrate the need for StartTransactionCommand and CommitTransactionCommand to be state smart -- they should call CommandCounterIncrement between the calls to BeginTransactionBlock and EndTransactionBlock and outside these calls they need to do normal start, commit or abort processing. 該例子想表達的意思是StartTransactionCommand和CommitTransactionCommand需要具備狀態智能 -- 在BeginTransactionBlock/EndTransactionBlock之間需調用CommandCounterIncrement, 在這些調用之外,它們需要執行常規的start,commit或abort處理. Furthermore, suppose the "SELECT * FROM foo" caused an abort condition. In this case AbortCurrentTransaction is called, and the transaction is put in aborted state. In this state, any user input is ignored except for transaction-termination statements, or ROLLBACK TO <savepoint> commands. 而且,假定"SELECT * FROM foo"出錯,導致需要abort,那么會調用AbortCurrentTransaction(bottom), 事務狀態為aborted狀態.事務處于這個狀態,除了事務終止語句或者ROLLBACK TO <savepoint>命令外,所有用戶輸入都會被忽略. Transaction aborts can occur in two ways: 事務取消的情況有兩種: 1) system dies from some internal cause (syntax error, etc) 內部原因,如語法錯誤等. 2) user types ROLLBACK 用戶類型的ROLLBACK. The reason we have to distinguish them is illustrated by the following two situations: 區分事務取消的原因如下兩例所示: case 1 case 2 ------ ------ 1) user types BEGIN 1) user types BEGIN 2) user does something 2) user does something 3) user does not like what 3) system aborts for some reason she sees and types ABORT (syntax error, etc) In case 1, we want to abort the transaction and return to the default state. In case 2, there may be more commands coming our way which are part of the same transaction block; we have to ignore these commands until we see a COMMIT or ROLLBACK. 第一種情況,用戶希望取消事務并返回到默認狀態. 第二種情況,在同一個事務塊中,可能會有更多的命令進入,需要忽略這些命令直至COMMIT/ROLLBACK. Internal aborts are handled by AbortCurrentTransaction, while user aborts are handled by UserAbortTransactionBlock. Both of them rely on AbortTransaction to do all the real work. The only difference is what state we enter after AbortTransaction does its work: * AbortCurrentTransaction leaves us in TBLOCK_ABORT, * UserAbortTransactionBlock leaves us in TBLOCK_ABORT_END 內部的事務取消通過AbortCurrentTransaction(bottom)處理,而用戶取消通過UserAbortTransactionBlock(top)處理. 它們都需要依賴AbortTransaction(bottom)來處理實際的工作,不同的地方是在AbortTransaction后進入的狀態不同: * AbortCurrentTransaction進入TBLOCK_ABORT * UserAbortTransactionBlock進入TBLOCK_ABORT_END Low-level transaction abort handling is divided in two phases: * AbortTransaction executes as soon as we realize the transaction has failed. It should release all shared resources (locks etc) so that we do not delay other backends unnecessarily. * CleanupTransaction executes when we finally see a user COMMIT or ROLLBACK command; it cleans things up and gets us out of the transaction completely. In particular, we mustn't destroy TopTransactionContext until this point. 底層事務取消處理分為兩個階段: * 一旦感知事務已失敗,則馬上執行AbortTransaction,需要釋放所有的共享資源(比如鎖等)以便不影響其他后臺進程. * 在用戶發出COMMIT/ROLLBACK時執行CleanupTransaction;清理現場并完整的跳出事務. 特別地,在這個點上才需要銷毀TopTransactionContext Also, note that when a transaction is committed, we don't close it right away. Rather it's put in TBLOCK_END state, which means that when CommitTransactionCommand is called after the query has finished processing, the transaction has to be closed. The distinction is subtle but important, because it means that control will leave the xact.c code with the transaction open, and the main loop will be able to keep processing inside the same transaction. So, in a sense, transaction commit is also handled in two phases, the first at EndTransactionBlock and the second at CommitTransactionCommand (which is where CommitTransaction is actually called). 同時,注意如果事務已提交,必須要馬上關閉,而是進入TBLOCK_END狀態, 這意味著在查詢完成后執行CommitTransactionCommand,事務才會關閉. 這種區別很微妙,但很重要,因為控制已在事務開啟的情況下從xact.c代碼中跳出,主循環仍在相同的主事務中. 因此,在某種意義上來說,事務提交存在兩個階段,首先EndTransactionBlock(top),其次CommitTransactionCommand(middle). (CommitTransactionCommand是實際調用CommitTransaction的地方) The rest of the code in xact.c are routines to support the creation and finishing of transactions and subtransactions. For example, AtStart_Memory takes care of initializing the memory subsystem at main transaction start. xact.c的剩余代碼是用于支持創建和結束事務和子事務的例程. 比如AtStart_Memory在主事務開啟時處理初始化內存子系統.
TransactionState結構體
/* * transaction states - transaction state from server perspective */ 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; /* * transaction block states - transaction state of client queries * * Note: the subtransaction states are used only for non-topmost * transactions; the others appear only in the topmost transaction. */ typedef enum TBlockState { /* not-in-transaction-block states */ TBLOCK_DEFAULT, /* idle */ TBLOCK_STARTED, /* running single-query transaction */ /* transaction block states */ TBLOCK_BEGIN, /* starting transaction block */ TBLOCK_INPROGRESS, /* live transaction */ TBLOCK_IMPLICIT_INPROGRESS, /* live transaction after implicit BEGIN */ TBLOCK_PARALLEL_INPROGRESS, /* live transaction inside parallel worker */ TBLOCK_END, /* COMMIT received */ TBLOCK_ABORT, /* failed xact, awaiting ROLLBACK */ TBLOCK_ABORT_END, /* failed xact, ROLLBACK received */ TBLOCK_ABORT_PENDING, /* live xact, ROLLBACK received */ TBLOCK_PREPARE, /* live xact, PREPARE received */ /* 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, /* failed subxact, ROLLBACK received */ TBLOCK_SUBABORT_PENDING, /* live subxact, ROLLBACK received */ TBLOCK_SUBRESTART, /* live subxact, ROLLBACK TO received */ TBLOCK_SUBABORT_RESTART /* failed subxact, ROLLBACK TO received */ } TBlockState; /* * transaction state structure */ typedef struct TransactionStateData { FullTransactionId fullTransactionId; /* my FullTransactionId */ SubTransactionId subTransactionId; /* my subxact ID */ char *name; /* savepoint name, if any */ int savepointLevel; /* savepoint level */ TransState state; /* low-level state */ TBlockState blockState; /* high-level state */ int nestingLevel; /* transaction nesting depth */ int gucNestLevel; /* GUC context nesting depth */ MemoryContext curTransactionContext; /* my xact-lifetime context */ ResourceOwner curTransactionOwner; /* my query resources */ TransactionId *childXids; /* subcommitted child XIDs, in XID order */ int nChildXids; /* # of subcommitted child XIDs */ int maxChildXids; /* allocated size of childXids[] */ Oid prevUser; /* previous CurrentUserId setting */ int prevSecContext; /* previous SecurityRestrictionContext */ bool prevXactReadOnly; /* entry-time xact r/o state */ bool startedInRecovery; /* did we start in recovery? */ bool didLogXid; /* has xid been included in WAL record? */ int parallelModeLevel; /* Enter/ExitParallelMode counter */ bool chain; /* start a new block after this one */ struct TransactionStateData *parent; /* back link to parent */ } TransactionStateData; typedef TransactionStateData *TransactionState;
“怎么理解PostgreSQL事務管理”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。