Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何捕获具有UOW副作用的函数的PostgreSQL回滚?_Postgresql_Transactions_Rollback - Fatal编程技术网

如何捕获具有UOW副作用的函数的PostgreSQL回滚?

如何捕获具有UOW副作用的函数的PostgreSQL回滚?,postgresql,transactions,rollback,Postgresql,Transactions,Rollback,我正在编写一个标量plpgsql函数,其中包含一个C函数,该函数在数据库之外有副作用。在某些任意SQL(触发器、选择、写入等)中调用函数时,我希望在PostgreSQL工作单元(UOW)边界上提交或回滚副作用。我可以处理UOW提交,但我不知道如何“捕获”数据库回滚和回滚副作用。关键的一点是,我正在编写函数,但无法控制如何调用它,也就是说,我不能“强制”调用位于具有异常处理程序的块中。有什么想法吗 对于提交,我计划将plpsql函数插入到一个数据库表中,该数据库表有一个触发器“…插入后…执行过程提

我正在编写一个标量plpgsql函数,其中包含一个C函数,该函数在数据库之外有副作用。在某些任意SQL(触发器、选择、写入等)中调用函数时,我希望在PostgreSQL工作单元(UOW)边界上提交或回滚副作用。我可以处理UOW提交,但我不知道如何“捕获”数据库回滚和回滚副作用。关键的一点是,我正在编写函数,但无法控制如何调用它,也就是说,我不能“强制”调用位于具有异常处理程序的块中。有什么想法吗

对于提交,我计划将plpsql函数插入到一个数据库表中,该数据库表有一个触发器“…插入后…执行过程提交\u我的\u side\u effect()”,因此当UOW提交时,行被提交,插入后触发器触发,presto,副作用被提交


到目前为止,我唯一的想法是将txid_current()传递给后台工作进程。然后在一些使用SPI的心跳上,检查txid是否处于飞行状态或未提交状态,然后它一定已回滚。但这似乎是一项繁重的工作。

从广义上讲,如果事务未提交且不再运行,则被视为“回滚”;为了符合ACID的要求,显式的
回滚
在功能上必须与拔下服务器上的电源线相同,因此一般来说,不会有任何与回滚相关的故意操作,您可能会连接到该操作

回滚数据的实际删除由处理,其工作方式或多或少类似于您建议的后台工作人员:由未运行且未提交的事务编写的任何内容都可能被删除。但是,还有更多的内容,因为包含子事务(
SAVEPOINT
s或PL/pgSQL
EXCEPTION
块)的事务可以部分回滚。换句话说,
txid\u current()
本身不足以决定是否提交了更改,我也不知道Postgres是否公开了足够的子事务状态信息,让您能够满足这一要求

我认为唯一明智的方法是将副作用的应用转移到外部进程,并在提交后触发它,一旦您知道实际提交了什么。我想到了两种方法:

  • 将PL/pgSQL函数插入到外部进程轮询的工作队列中,或者
  • 通过将更改反馈给流程(通知仅在提交时传递,来自回滚子事务的通知将被丢弃)

通知更轻量级,延迟更低(它们是异步传递的,因此不需要轮询),但不如基于表的方法健壮,因为在发生崩溃或意外断开连接时通知队列会被清除。当然,如果您希望碰撞安全性而不存在轮询的缺点,您可以同时执行这两项操作。

广义而言,如果事务未提交且不再运行,则事务被视为“回滚”;为了符合ACID的要求,显式的
回滚
在功能上必须与拔下服务器上的电源线相同,因此一般来说,不会有任何与回滚相关的故意操作,您可能会连接到该操作

回滚数据的实际删除由处理,其工作方式或多或少类似于您建议的后台工作人员:由未运行且未提交的事务编写的任何内容都可能被删除。但是,还有更多的内容,因为包含子事务(
SAVEPOINT
s或PL/pgSQL
EXCEPTION
块)的事务可以部分回滚。换句话说,
txid\u current()
本身不足以决定是否提交了更改,我也不知道Postgres是否公开了足够的子事务状态信息,让您能够满足这一要求

我认为唯一明智的方法是将副作用的应用转移到外部进程,并在提交后触发它,一旦您知道实际提交了什么。我想到了两种方法:

  • 将PL/pgSQL函数插入到外部进程轮询的工作队列中,或者
  • 通过将更改反馈给流程(通知仅在提交时传递,来自回滚子事务的通知将被丢弃)

通知更轻量级,延迟更低(它们是异步传递的,因此不需要轮询),但不如基于表的方法健壮,因为在发生崩溃或意外断开连接时通知队列会被清除。当然,如果你想在没有轮询缺点的情况下实现崩溃安全,你可以同时做到这两个方面。

我发现了一个名为“错误”回滚的功能,并查看了它的实现,我认为我可以使用以下伪代码“包装”所有SQL命令,添加“假”保存点,以及“假”回滚到保存点并触发“回滚”副作用()“:


我可能需要一个_保存点堆栈。我将使用它运行!

我发现了一个名为_ERROR_ROLLBACK的功能,并查看了它的实现,我认为我可以使用以下伪代码“包装”所有SQL命令,以添加“假”保存点,以及“假”回滚到保存点,并触发一个“ROLLBACK_side_effect()”:


我可能需要一堆_savepoint。我会用它运行的!

谢谢尼克,在频道上通知是一个很好的建议,但它不允许在正确的时间激发副作用。谢谢尼克,在频道上通知是一个很好的建议,但它不允许在正确的时间激发副作用。
side_effect_fired = false; // set true if the side_effect udf called
run("SAVEPOINT _savepoint");
run($sqlcommand);
if (txn_status == ERROR && side_effect_fired) {
   run("ROLLBACK TO _savepoint"
   rollback_side_effect()); // rollback the side effect
}