怎么理解PostgreSQL事務(wù)管理中的子事務(wù)

本篇內(nèi)容主要講解“怎么理解PostgreSQL事務(wù)管理中的子事務(wù)”,感興趣的朋友不妨來看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“怎么理解PostgreSQL事務(wù)管理中的子事務(wù)”吧!

10多年的北海網(wǎng)站建設(shè)經(jīng)驗(yàn),針對(duì)設(shè)計(jì)、前端、開發(fā)、售后、文案、推廣等六對(duì)一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。全網(wǎng)營(yíng)銷推廣的優(yōu)勢(shì)是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動(dòng)調(diào)整北海建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。創(chuàng)新互聯(lián)公司從事“北海網(wǎng)站設(shè)計(jì)”,“北海網(wǎng)站推廣”以來,每個(gè)客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。

一、Subtransaction Handling

README

Subtransaction Handling
-----------------------
子事務(wù)處理
Subtransactions are implemented using a stack of TransactionState structures,
each of which has a pointer to its parent transaction's struct.  When a new
subtransaction is to be opened, PushTransaction is called, which creates a new
TransactionState, with its parent link pointing to the current transaction.
StartSubTransaction is in charge of initializing the new TransactionState to
sane values, and properly initializing other subsystems (AtSubStart routines).
子事務(wù)通過TransactionState結(jié)構(gòu)體棧來實(shí)現(xiàn),每一個(gè)TransactionState都有指向其父事務(wù)結(jié)構(gòu)體的指針.
新的子事務(wù)即將開啟時(shí),調(diào)用PushTransaction,該函數(shù)創(chuàng)建TransactionState結(jié)構(gòu)體,parent指向當(dāng)前事務(wù).
StartSubTransaction負(fù)責(zé)完整初始化新的TransactionState結(jié)構(gòu)體,并正確初始化其他子系統(tǒng)(AtSubStart例程實(shí)現(xiàn)).
When closing a subtransaction, either CommitSubTransaction has to be called
(if the subtransaction is committing), or AbortSubTransaction and
CleanupSubTransaction (if it's aborting).  In either case, PopTransaction is
called so the system returns to the parent transaction.
在關(guān)閉子事務(wù)時(shí),成功則調(diào)用CommitSubTransaction,取消/失敗則調(diào)用AbortSubTransaction和CleanupSubTransaction.
無論哪種情況,都會(huì)調(diào)用PopTransaction以便返回到父事務(wù).
One important point regarding subtransaction handling is that several may need
to be closed in response to a single user command.  That's because savepoints
have names, and we allow to commit or rollback a savepoint by name, which is
not necessarily the one that was last opened.  Also a COMMIT or ROLLBACK
command must be able to close out the entire stack.  We handle this by having
the utility command subroutine mark all the state stack entries as commit-
pending or abort-pending, and then when the main loop reaches
CommitTransactionCommand, the real work is done.  The main point of doing
things this way is that if we get an error while popping state stack entries,
the remaining stack entries still show what we need to do to finish up.
子事務(wù)處理一個(gè)很很重要的點(diǎn)是為了響應(yīng)單個(gè)用戶命令需要關(guān)閉多個(gè)子事務(wù).
這是因?yàn)閷?duì)于命名savepoints,PG允許通過名稱提交或回滾至這些savepoint,而這些savepoint并不需要是最后才打開的那個(gè).
同時(shí),COMMIT/ROLLBACK命令必須可以關(guān)閉整個(gè)棧.
通過工具命令子例程來標(biāo)記整個(gè)狀態(tài)棧為commit-pending或者是abort-pending,
然后在主循環(huán)到達(dá)CommitTransactionCommand時(shí),執(zhí)行實(shí)際的commit/abort.
以這種方法做這些事情的主要關(guān)注點(diǎn)是如果在棧條目出棧時(shí)出現(xiàn)錯(cuò)誤,剩余的棧條目仍然可以展示我們需要做什么才能完結(jié).
In the case of ROLLBACK TO <savepoint>, we abort all the subtransactions up
through the one identified by the savepoint name, and then re-create that
subtransaction level with the same name.  So it's a completely new
subtransaction as far as the internals are concerned.
在ROLLBACK TO <savepoint>這種情況中,我們?nèi)∠藦膕avepoint name到當(dāng)前的所有子事務(wù),
然后使用相同的名稱重建了該子事務(wù).因此這是內(nèi)部需要關(guān)注的完全的子事務(wù).
Other subsystems are allowed to start "internal" subtransactions, which are
handled by BeginInternalSubTransaction.  This is to allow implementing
exception handling, e.g. in PL/pgSQL.  ReleaseCurrentSubTransaction and
RollbackAndReleaseCurrentSubTransaction allows the subsystem to close said
subtransactions.  The main difference between this and the savepoint/release
path is that we execute the complete state transition immediately in each
subroutine, rather than deferring some work until CommitTransactionCommand.
Another difference is that BeginInternalSubTransaction is allowed when no
explicit transaction block has been established, while DefineSavepoint is not.
其他子系統(tǒng)允許通過BeginInternalSubTransaction函數(shù)啟動(dòng)"internal"子事務(wù).
因此可以在諸如PL/pgSQL等編程語言中可以實(shí)現(xiàn)異常處理.
ReleaseCurrentSubTransaction和RollbackAndReleaseCurrentSubTransaction允許子系統(tǒng)關(guān)閉子事務(wù).
這種方式跟savepoint/release的不同點(diǎn)是在每一個(gè)子例程中我們馬上執(zhí)行了完整的狀態(tài)變換,
而不是等到執(zhí)行CommitTransactionCommand才執(zhí)行某些工作.
另外一個(gè)不同點(diǎn)是在沒有創(chuàng)建顯式事務(wù)塊的情況下允許調(diào)用BeginInternalSubTransaction,
而savepoint則需要明確的DefineSavepoint.
Transaction and Subtransaction Numbering
----------------------------------------
事務(wù)和子事務(wù)編號(hào)
Transactions and subtransactions are assigned permanent XIDs only when/if
they first do something that requires one --- typically, insert/update/delete
a tuple, though there are a few other places that need an XID assigned.
If a subtransaction requires an XID, we always first assign one to its
parent.  This maintains the invariant that child transactions have XIDs later
than their parents, which is assumed in a number of places.
事務(wù)和子事務(wù)在需要時(shí)才會(huì)分配持久的XIDs,典型的場(chǎng)景是insert/update/delete元組.
如果子事務(wù)需要XID,首先會(huì)給其父事務(wù)分配一個(gè),這保證了子事務(wù)編號(hào)在父事務(wù)之后.
The subsidiary actions of obtaining a lock on the XID and entering it into
pg_subtrans and PG_PROC are done at the time it is assigned.
分配事務(wù)號(hào)還需要做的事情是在XID獲取鎖/寫入到pg_subtrans和PG_PROC中.
A transaction that has no XID still needs to be identified for various
purposes, notably holding locks.  For this purpose we assign a "virtual
transaction ID" or VXID to each top-level transaction.  VXIDs are formed from
two fields, the backendID and a backend-local counter; this arrangement allows
assignment of a new VXID at transaction start without any contention for
shared memory.  To ensure that a VXID isn't re-used too soon after backend
exit, we store the last local counter value into shared memory at backend
exit, and initialize it from the previous value for the same backendID slot
at backend start.  All these counters go back to zero at shared memory
re-initialization, but that's OK because VXIDs never appear anywhere on-disk.
沒有XID的事務(wù)仍然需要進(jìn)行標(biāo)識(shí),特別是需要持有鎖的時(shí)候.
出于這個(gè)目的,我們分配了"虛擬事務(wù)號(hào)"(即VXID)給每一個(gè)頂層事務(wù).
VXIDs由兩個(gè)域組成,后臺(tái)進(jìn)程ID和后臺(tái)進(jìn)程本地計(jì)數(shù)器;這樣的編號(hào)產(chǎn)生方法不需要共享內(nèi)存爭(zhēng)用就可以進(jìn)行新VXID的分配.
為了確保在后臺(tái)進(jìn)程退出后VXID不會(huì)過快的被使用,我們把最后的本地計(jì)數(shù)器值存儲(chǔ)到共享內(nèi)存中,
對(duì)于同一個(gè)后臺(tái)進(jìn)程ID,分配先前存儲(chǔ)的計(jì)數(shù)器值給這個(gè)新的后臺(tái)進(jìn)程.
在共享內(nèi)存重新初始化后這些計(jì)數(shù)器會(huì)歸零,由于不會(huì)出現(xiàn)落盤,因此這樣的處理沒有任何問題.
Internally, a backend needs a way to identify subtransactions whether or not
they have XIDs; but this need only lasts as long as the parent top transaction
endures.  Therefore, we have SubTransactionId, which is somewhat like
CommandId in that it's generated from a counter that we reset at the start of
each top transaction.  The top-level transaction itself has SubTransactionId 1,
and subtransactions have IDs 2 and up.  (Zero is reserved for
InvalidSubTransactionId.)  Note that subtransactions do not have their
own VXIDs; they use the parent top transaction's VXID.
在內(nèi)部實(shí)現(xiàn)上,不論子事務(wù)是否擁有XIDs,后臺(tái)進(jìn)程需要標(biāo)識(shí)子事務(wù)的方法;只要父頂級(jí)事務(wù)存在這種需求就好一直存在.
因此,產(chǎn)生了SubTransactionId,該字段類似于CommandId,在每次頂層事務(wù)都會(huì)重置的計(jì)數(shù)器.
頂層事務(wù)本身的SubTransactionId設(shè)定為1,其他子事務(wù)的ID為2或更大(0保留用于InvalidSubTransactionId).
注意子事務(wù)沒有VXIDs;它們使用頂層事務(wù)的VXID.

TransactionState結(jié)構(gòu)體

/*
 *    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;

到此,相信大家對(duì)“怎么理解PostgreSQL事務(wù)管理中的子事務(wù)”有了更深的了解,不妨來實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

網(wǎng)頁題目:怎么理解PostgreSQL事務(wù)管理中的子事務(wù)
網(wǎng)頁URL:http://muchs.cn/article42/ppjhec.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站設(shè)計(jì)、響應(yīng)式網(wǎng)站ChatGPT、軟件開發(fā)、網(wǎng)站制作靜態(tài)網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

h5響應(yīng)式網(wǎng)站建設(shè)