【问题标题】:Can simple UPDATE and DELETE statements trigger deadlocks and rollback in PostgreSQL?简单的 UPDATE 和 DELETE 语句可以在 PostgreSQL 中触发死锁和回滚吗?
【发布时间】:2014-03-28 17:14:24
【问题描述】:

当在同一张表上同时执行其他更复杂的语句时,触发器中执行的简单 UPDATEDELETE 语句是否会导致死锁或回滚?

UPDATE "s_mat"
    SET "req_st" = my_st, "l_upd" = retr
    WHERE "req_id" = my_id;

DELETE FROM "mat" WHERE "req_id" = my_id;

我是否应该预期这些语句可能出现 deadlock_detectedtransaction_rollback 异常?

【问题讨论】:

    标签: sql postgresql concurrency triggers deadlock


    【解决方案1】:

    基本上是的。如果两个触发器同时在两个单独的事务中运行,我们称它们为 t1 和 t2:

    t1                t2
    update row x
                     update row y
    delete row y
                     delete row x
    

    这会陷入僵局。 Postgres 自动检测条件并中止除一个竞争事务之外的所有事务。 Details in the manual.

    如果您的所有代码都以相同(确定的)顺序处理行,则不会发生这种情况。但有时这无法保证。

    如果您使用排他锁(按规范顺序)锁定要处理的所有行manually,则可以显着减少死锁的机会。

    绝对确定,使用SERIALIZABLE 事务隔离运行。您必须为序列化失败准备代码并在这种情况下重试。

    可序列化模式下的事务较慢,仅应在必要时使用。如果您没有面临繁重的并发负载或代码中没有关键的语句组合,则使用默认(更快)READ COMMITTED 隔离级别可能会很好。

    优化代码的性能并最​​大限度地减少竞争条件的机会窗口可能会长期。除了始终以相同的顺序处理行之外,您还可以使用data-modifying CTEsUPDATEDELETE 组合在一个语句中。不排除竞态条件,但最大限度地减少死锁的时间范围。详细示例:

    【讨论】:

    • 好的,我想 SERIALIZABLE 是适合我的方式。在这种情况下,我需要仅检查“serialization_failure”还是检查所有 40 类 - 事务回滚异常?
    • @JVerstry:其他一切都保持不变。回滚只发生在异常之后(除非手动触发)并且永远不会发生。为任何异常准备代码不会有什么坏处。但是你应该只在有意义的地方重试(比如序列化失败)。注意不要在这里触发无限循环。我在答案中添加了更多内容。
    猜你喜欢
    • 1970-01-01
    • 2020-03-21
    • 1970-01-01
    • 1970-01-01
    • 2019-01-28
    • 1970-01-01
    • 2012-05-01
    • 1970-01-01
    • 2019-07-31
    相关资源
    最近更新 更多