为什么在合并实例时PostgreSQL不增加id_sequence的last_value?

1 投票
2 回答
907 浏览
提问于 2025-04-16 23:30

在之前的一个问题中,我在想,为什么在第一次把一个带有ID的实例合并到数据库时,会收到一个完整性错误(就是在注入一些固定数据的时候)。

不过,我学会了通过调用我正在注入的最高索引来解决这个问题:

select setval('my_items_id_seq', {id});

但是,这并没有解决根本的问题,这也是我现在正在努力解决的。为什么在插入新行时,合并操作不调用nextval()这个序列呢?

2 个回答

0

我之前也遇到过在PostgreSQL中出现完整性错误的问题,直到我看到这篇帖子。我决定遵循一个规则:如果数据库中没有这个对象,就不要在使用db.add()或db.merge()时指定主键。

下面是我用来理解wberry意思的一些例子。

# Suppose the next value of rows_id_seq will be 33.
# You run the following code.
db.add(Row(id=35))
# Since you specified a primary key, SQLAlchemy will NOT increment rows_id_seq,
# so the next value of rows_id_seq will still be 33.
db.add(Row())
# The next value of rows_id_seq will be 34
db.add(Row())
# The next value of rows_id_seq will be 35
db.add(Row())
db.query(Row.id).all() # Uh-oh
# (IntegrityError) duplicate key value violates unique constraint "rows_pkey"
# Key (id)=(35) already exists.

这里是一个使用db.merge()的例子。

# Suppose the next value of rows_id_seq will be 1.
# You run the following code.
db.merge(Row(id=1))
db.merge(Row(id=2))
db.merge(Row(id=3))
# Since you specified a primary key, SQLAlchemy will NOT increment rows_id_seq,
# so the next value of rows_id_seq will still be 1.
db.merge(Row())
db.query(Row.id).all() # Uh-oh
# (IntegrityError) duplicate key value violates unique constraint "rows_pkey"
# Key (id)=(1) already exists.
3

如果你的对象已经设置了主键(PK)属性,那么数据库就不会使用ID序列,也不会增加这个序列的值。因为在这种情况下,数据库没有必要执行一个隐式的插入操作,比如 insert into mytable (id, ...) values ((select nextval from mytable_id_seq), ...)

你确定需要对你的 session 使用 merge 而不是 add 吗?如果你真的在插入数据,我觉得这更像是一个 add 操作。如果你只是重新使用一个仍在内存中的对象,而这个对象之前已经添加过,并且现在可能在数据库中发生了变化,那么使用 merge 是合适的。

撰写回答