怎么理解PostgreSQL事务管理
本篇内容介绍了“怎么理解PostgreSQL事务管理”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
黄陵ssl适用于网站、小程序/APP、API接口等需要进行数据传输应用场景,ssl证书未来市场广阔!成为创新互联的ssl证书销售渠道,可以享受市场价格4-6折优惠!如果有意向欢迎电话联系或者加微信:18980820575(备注:SSL证书合作)期待与您的合作!
一、The Transaction System
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 TOcommands. 而且,假定"SELECT * FROM foo"出错,导致需要abort,那么会调用AbortCurrentTransaction(bottom), 事务状态为aborted状态.事务处于这个状态,除了事务终止语句或者ROLLBACK TO 命令外,所有用户输入都会被忽略. 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事务管理”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注创新互联网站,小编将为大家输出更多高质量的实用文章!
新闻标题:怎么理解PostgreSQL事务管理
网站路径:http://scgulin.cn/article/pdohip.html