postgresql 为什么即使对象创建失败,Postgres序列项也会上升?

k7fdbhmy  于 2023-04-29  发布在  PostgreSQL
关注(0)|答案(1)|浏览(110)

我有一个Postgres项目,其中一个模型是Client,只是按主键索引。我在创建客户端时遇到了一个问题,因为沿着某个地方,有人创建了一个客户端,同时显式地设置了它的主键,我读到的主键并没有影响Postgres的客户端序列表,它负责在创建客户端对象时自动递增主键1。
我运行了一些SQL查询来处理它,发现当前序列值实际上比数据库中客户端的最高id 263低1,即262,所以它说ID为263的客户端已经存在。我尝试在我们的前端应用程序中创建一个客户端,再次得到错误,并决定重新运行查询。我看到数据库中没有创建新的客户端,正如预期的那样,但我也注意到序列值确实上升到263,所以当我再次尝试创建客户端时,它工作了!
即使相关模型的创建失败,PostgreSQL序列表也会向上递增,这是正常的行为吗?如果是这样的话,这可能会导致一些严重的问题。

acruukt9

acruukt91#

这是预期的行为。See docs
Nextval
将序列对象前进到它的下一个值并返回该值。这是以原子方式完成的:即使多个会话同时执行Nextval,每个会话也将安全地接收不同的序列值。
如果序列对象是用默认参数创建的,那么连续的nextval调用将返回从1开始的连续值。其他行为可以通过CREATE SEQUENCE命令中的特殊参数获得;有关详细信息,请参阅其命令参考页。

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

请注意,nextval通常设置为自动增量/串行列的默认值。
还可以试着想象一下,如果nextval回滚,那将是多么困难和低效。本质上,您必须锁定nextval上的每个客户端,直到整个事务(获得锁的事务)被处理。在这种情况下,忘记并发插入。
如果是这样的话,这可能会导致一些严重的问题。
比如什么?在您的案例中,问题是有人手动指定了自动增量列的值。除非你是一个武士,否则你永远不应该这样做。:)

相关问题