【问题标题】:How to write changes to database when within a begin/commit/rollback block在开始/提交/回滚块内如何将更改写入数据库
【发布时间】:2014-09-03 09:56:33
【问题描述】:

我们已经实现了一个数据库开始/提交/回滚系统,您可以在任何地方的代码中开始/提交,如果在特定位置执行开始/提交时,您就在另一个开始/提交块中,那么它只会在您回到开始的第一级时进行提交。这是使用静态变量完成的,该变量只记录您所在的开始/提交块级别。每次遇到开始时,如果计数器为 1,则将 BEGIN 发送到数据库并递增计数器。如果计数器大于一,则只增加计数器。同样,如果请求提交,则计数器会递减,并且只有在计数器为 1 的情况下,才会向数据库发送真正的 COMMIT 命令。

首先,对这种方式有什么想法吗?长期以来,这对我们来说非常有效。但是,我们现在遇到了一种情况,无论我们在开始/提交级别方面处于什么位置,我们都需要将一些数据保存到数据库中。

人们一般如何处理这个问题?另外对我们处理多级开始/提交的方式有何想法?

顺便说一句,我们在 PHP 中使用 postgres 数据库进行此操作。

谢谢 齐亚德

【问题讨论】:

  • 您最好的选择是创建一个单独的事务(或连接,取决于实现)来运行您希望保证的插入。
  • 您不能在单个连接/事务中执行此操作。对于嵌入式事务,请参阅SAVEPOINTs postgresql.org/docs/current/static/sql-savepoint.html
  • 这个功能通常被称为“自治事务”,在 PostgreSQL 中不存在。解决方法始终是打开一个新连接。考虑用于服务器端实现的 dblink 模块。

标签: php database postgresql


【解决方案1】:

您所描述的几乎是 JTA(Java 事务 API)如何管理 EJB3 中的声明性事务范围。您将方法标记为需要事务,如果没有事务打开,则开始一个事务。事务结束由开始事务的方法的结尾来描述。

但是,我们现在遇到了一种情况,我们确实需要将一些数据保存到数据库中,而不管我们在开始/提交级别方面处于什么位置。

您将需要一种新的连接方式,因为 PostgreSQL 不支持自治事务 - 暂停事务、执行其他操作和恢复事务,或者仅提交部分事务交易。

当你有一个方法说REQUIRES_NEW 时,JTA 通过在幕后与服务器建立一个新的 JDBC 连接来处理这个问题。该方法要求即使有一个打开的事务,该事务也被暂停,而是开始一个新的事务。由于 PostgreSQL 不支持,JTA 模拟它。

你也会想做同样的事情,我强烈建议你研究一下 JTA 是如何做事的。对于 Java API,它出奇地不糟糕。


PHP 特有的因素:PHP 喜欢缓存连接,因此多次连接尝试通常会返回相同的连接句柄。对PGSQL_CONNECT_FORCE_NEW 使用pg_connect 选项,或者(最好)使用PDO,它不会返回缓存的连接,除非你用PDO::ATTR_PERSISTENT 明确告诉它。


顺便说一句,您可能不知道保存点。

如果您看到嵌套的BEGIN,您可以将其更改为SAVEPOINT [savepointname]ROLLBACK 变为 ROLLBACK TO SAVEPOINT [savepointname]COMMIT 只是 RELEASE SAVEPOINT [savepointname] - 即“我不希望回滚到这个,如果外部事务提交,那么我的应该”。

不过,保存点不是免费的,因此您应该仅在您可能确实需要回滚子事务时才使用它们。

如果外部事务回滚,您不能以保留的方式提交子事务,但是当您运行可能 ERROR 作为大型、昂贵事务的一部分的事情时,它们仍然非常方便。

【讨论】:

  • 我忘了提到我们认为我们需要一个新的连接,以便该连接上的事务是独立的,并尝试过,但没有奏效。我认为问题在于您指出的有关 PHP 缓存连接的内容,因此我们实际上获得了相同的连接。感谢您指出这一点,它现在正在工作。感谢所有评论的人。
  • @Ziad 很高兴为您提供帮助。您应该考虑转向 PDO。它得到了维护(与遗留的 postgres 不同)并且更少损坏。并不是说“没有损坏”,因为这仍然是 PHP,但损坏程度要小得多 - 例如,bytea 支持可以正常工作。
猜你喜欢
  • 1970-01-01
  • 2011-08-26
  • 2019-10-29
  • 1970-01-01
  • 1970-01-01
  • 2012-01-08
  • 1970-01-01
  • 2012-03-28
  • 1970-01-01
相关资源
最近更新 更多