2

我很感兴趣,避免这个小问题的最佳做法是什么:)

让我们使用 2 个客户端,它们都试图在具有唯一约束的表中插入行。
假设它是“url”列。

一次可能会出现以下情况:
  1) Client A 看,表中是否有 url "a"
  2) Client A 得到答案,没有那个 url
  3) Client A 要插入 url "a"
  4) 客户 B 看,表中是否有 url "a"
  5) 客户 B 得到答案,没有那个 url
  6) 客户 A 插入 url "a"
  7) 客户 B 将插入 url "a",但得到重复键错误

我是否理解正确,避免它的最佳方法 - 只是在应用程序级别重试?

4

2 回答 2

2

您可以通过在事务开始时取出显式锁来避免错误,但这可能对并发性和吞吐量不利。

http://www.postgresql.org/docs/current/interactive/explicit-locking.html

如果您不阻止并发尝试,则需要以一种或另一种方式处理重试。您可以将其封装在一个函数中,而不是将该逻辑放在应用程序代码中。逻辑类似于 merge_db() 示例:

http://www.postgresql.org/docs/current/interactive/plpgsql-control-structures.html#PLPGSQL-ERROR-TRAPPING

于 2012-05-04T12:39:23.900 回答
1

如果在 SERIALIZABLE 隔离级别下运行,客户端 B 将被迫等待 A 的事务完成,然后返回 url 的值。由于该值尚不存在,因此您无法在记录上加锁(没有记录),因此将使用索引上的间隙锁定。但正如@kgrittn 提到的,这会对性能和并发性产生负面影响。所以最好处理重复键错误

于 2012-05-04T12:48:35.343 回答