【问题标题】:Why does Postgres sequence item go up even if object creation fails?为什么即使对象创建失败,Postgres 序列项也会上升?
【发布时间】:2018-11-11 23:37:39
【问题描述】:

我有一个 Postgres 项目,其中我的一个模型是 Client 简单地按其主键索引。我在创建客户端时遇到了问题,因为有人在创建客户端的同时明确设置了我读过的主键并不会影响 Postgres 的客户端序列表,它负责在任何时候自动递增主键 1创建一个客户端对象。

我运行了一些 SQL 查询来玩弄它,发现当前的序列值实际上比数据库中客户端的最高 ID 263 低 1,即 262,所以它说的是 ID 为 263 的客户端已经存在。我尝试在我们的前端应用程序中创建一个客户端,再次遇到错误,并决定重新运行查询。我看到数据库中没有像预期的那样创建新的客户端,但我也注意到序列值确实上升到了 263,所以当我再次尝试创建客户端时它成功了!

即使创建相关模型失败,PostgreSQL 序列表也会增加这种正常行为吗?如果是这样,这似乎会导致一些严重的问题。

【问题讨论】:

    标签: postgresql sequence


    【解决方案1】:

    是的,这是预期的行为。 See docs:

    下一个

    将序列对象推进到下一个值并返回该值。这是原子完成的:即使多个会话同时执行 nextval,每个会话都将安全地接收到不同的序列值。

    如果已经使用默认参数创建了一个序列对象,则连续的 nextval 调用将返回从 1 开始的连续值。其他行为可以通过在 CREATE SEQUENCE 命令中使用特殊参数来获得;有关详细信息,请参阅其命令参考页面。

    重要提示:为避免阻塞从同一序列中获取数字的并发事务,nextval 操作永远不会回滚;也就是说,一旦获取了一个值,它就被认为是已使用的,即使执行 nextval 的事务稍后中止。这意味着中止的事务可能会在赋值序列中留下未使用的“漏洞”。

    请注意,nextval 通常设置为自动增量/序列列的默认值。

    还可以想象一下,如果 nextval 回滚会是多么困难和低效。本质上,您必须将每个客户端锁定在nextval 上,直到处理整个事务(获得锁定的事务)。在这种情况下,忘记并发插入。

    如果是这样,这似乎会导致一些严重的问题。

    比如什么?您的问题是有人手动为自动增量列指定了一个值。除非您是武士,否则您永远不应该这样做。 :)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-11-06
      • 2012-08-21
      • 2021-06-20
      • 2018-09-25
      • 1970-01-01
      • 1970-01-01
      • 2018-05-24
      相关资源
      最近更新 更多