2

可能重复:
如果在 PostgreSQL 中插入失败,有没有办法避免调用 nextval()?
Rails - Postgres 不会重用已删除的 ID,但 MySql 会重用吗?

我有PostgreSQL 9.2.1的非常简单的数据库。当我使用此方法插入Doctrine2的内容时:

$em->persist($entity);
$em->flush();

如果我收到错误

- 表示未插入记录-

它仍然添加1到我的主键中。所以如果我刷新页面50时间,它会说自动增量值设置为50。我怎样才能防止这种情况?如果没有插入记录,那么为什么主键会增加。这是非常关键的,因为它没有使用索引,而且数量还在不断增加。

我不知道它来自什么,为什么,所以,我没有尝试任何东西。非常卡在这一点上。

4

2 回答 2

5

Doctrine2 使用事务来完成它的任务。

每次 Doctrine 将其更改刷新到数据库时,它都会打开一个事务,准备好每条记录,然后提交将立即执行所有更改。

在此过程中,将分配需要auto_incrementID 的记录。如果记录在提交阶段失败,则不会添加记录,但自动增量已发出该 ID。

您可以在此处阅读有关事务的更多信息:http ://www.postgresql.org/docs/current/static/tutorial-transactions.html

注意:这对于 MySQL 也是一样的,我相信对于许多其他 RDBMS 也是一样的。

于 2012-10-21T00:36:14.817 回答
2

没有办法避免您观察到的行为,而不会导致严重的性能损失或不正确的并发操作。

自动递增字段是通过将字段绑定到序列来实现的default nextval('seqeunce_name')

序列旨在保证即使在并发操作下它们也始终发出唯一值。他们不能保证他们总是发出顺序值。当nextval()您尝试插入行时调用时,该值将被发出并且永远不会被序列再次发出,除非您使用手动重置序列setval()

由于安全地递增序列必然会产生锁定开销,因此在高并发操作下,一些 dbms 系统将为每个事务或会话缓存一组序列值以避免过度锁定——这进一步加剧了跳过序列值问题。在 postgres 中,这种值的缓存是通过CACHE cache序列创建的子句控制的。

于 2012-10-21T01:05:30.627 回答