简单的 UPDATE 和 DELETE 语句可以在 PostgreSQL 中触发死锁和回滚吗?
Posted
技术标签:
【中文标题】简单的 UPDATE 和 DELETE 语句可以在 PostgreSQL 中触发死锁和回滚吗?【英文标题】:Can simple UPDATE and DELETE statements trigger deadlocks and rollback in PostgreSQL? 【发布时间】:2014-03-28 17:14:24 【问题描述】:当在同一张表上同时执行其他更复杂的语句时,触发器中执行的简单 UPDATE
和 DELETE
语句是否会导致死锁或回滚?
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_detected
或 transaction_rollback
异常?
【问题讨论】:
【参考方案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 CTEs 将UPDATE
和DELETE
组合在一个语句中。不排除竞态条件,但最大限度地减少死锁的时间范围。详细示例:
【讨论】:
好的,我想 SERIALIZABLE 是适合我的方式。在这种情况下,我需要仅检查“serialization_failure”还是检查所有 40 类 - 事务回滚异常? @JVerstry:其他一切都保持不变。回滚只发生在异常之后(除非手动触发)并且永远不会发生。为任何异常准备代码不会有什么坏处。但是你应该只在有意义的地方重试(比如序列化失败)。注意不要在这里触发无限循环。我在答案中添加了更多内容。以上是关于简单的 UPDATE 和 DELETE 语句可以在 PostgreSQL 中触发死锁和回滚吗?的主要内容,如果未能解决你的问题,请参考以下文章
ruby 从New Relic获取一个查询语句的粘贴并解释所有这些语句;现在还可以转换UPDATE和DELETE
SQL注入之初窥insert,update,delete注入
在不提交的情况下测试 (JUnit) SQL DELETE 和 UPDATE 语句
spring data jpa执行update和delete语句时报错处理
MySQL之DML语句(insert update delete)
SQL Server Profiler 2008 怎么追踪特定种类语句如 insert,update,delete,能指定某个数据追踪吗