如何在 postgresql 中使一个事务先于另一个事务?

问题描述 投票:0回答:1

我有2张具有一对多关系的表。

表A 表B
id id
正在运行 a_id
正在运行

我正在做这样的事情:

交易1 交易2 交易3
UPDATE table_a SET is_running = false WHERE id=1
INSERT INTO table_b values (3, 1, true)
UPDATE table_b SET is_running = false WHERE id=2
SELECT id FROM table_b WHERE a_id=1 AND is_running=true
SELECT * FROM table_a WHERE id=1 AND is_running=true
  • 事务1更新A并获取所有正在运行的相关B。

  • 仅当相关 A 正在运行时,事务 2 才会向 table_b 中插入一行。

  • 事务 3 更新 table_b 中的一行。

我希望有3>1>2这样的优先策略。换句话说:

  • 如果事务 2 检测到事务 1 已提交,则它会回滚。

  • 事务 1 将等待事务 3 提交,以便它选择的行是最新的。

我尝试将事务2中的

SELECT
设置为
FOR UPDATE
以确保序列化,但这不符合我的需求,因为事务2在提交事务1时应该被迫回滚。

database postgresql transactions
1个回答
0
投票

如果在同一个数据库连接上一个接一个地运行这三个事务,那么严格序列化这三个事务是微不足道的……但这显然不是正在发生的情况,并且这三个事务必须在不同的会话中运行。

如果要序列化它们,则需要协调运行语句的会话。您可以通过不同的方式做到这一点:

  • 从一开始就对受事务影响的所有表采取显式

    ACCESS EXCLUSIVE
    锁定。

    那是愚人之道。它将阻止所有并发访问,如果您经常这样做,您将与 autovacuum 发生冲突,而 autovacuum 永远无法完成表的处理。

  • 采用事务级咨询锁来显式协调事务。

    这是一种不错的方法,但您必须显式地对其进行编码。

  • 协调应用程序端的会话。

    这也可以很好地工作,但超出了数据库的范围。

  • 使用

    SERIALIZABLE
    隔离级别。

    这是最好的方法。您试图避免的问题是“事务异常”,即在串行执行中永远不会发生的影响。通过SERIALIZABLE隔离,保证您不会出现异常情况。

    您付出的代价是其中一笔交易将出现

    序列化错误

    ,在这种情况下由应用程序重试该交易。

  • 请注意,我的解决方案都没有提供您想要的三笔交易的严格顺序。它们只是防止 then 以产生不良结果的方式同时运行。这通常是一致性所需要的。

如果这三个事务确实必须以某种确定性的顺序发生,那么您可能真的应该在单个数据库会话中运行它们。

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.