使用带有 PostgreSQL (8.x) 后端的 Django,我有一个模型,我需要跳过一个 id block ,例如在发出 49999 之后,我希望下一个 id 是 70000 而不是 50000(因为该 block 是为另一个源保留的,其中实例是用 id 显式添加的——我知道这不是一个很好的设计,但这是我必须使用的)。
执行此操作的正确/最安全的地方是什么?
我知道我可以设置顺序
SELECT SETVAL(
(SELECT pg_get_serial_sequence('myapp_mymodel', 'id')),
70000,
false
);
但是 Django 何时真正从序列中提取数字? 我是否重写 MyModel.save(),调用它的 super 然后捕获我的光标并检查
SELECT currval(
(SELECT pg_get_serial_sequence('myapp_mymodel', 'id'))
);
?
我相信即使保存模型失败,django 也可能会推进一个序列,所以我想确保每当它达到那个数字时它就会推进 - 有比 save() 更好的地方吗?
P.S.:即使那是要走的路——我真的能像这样计算出 save() session 的当前值吗?如果我获取一个连接和游标,并执行第二个 SQL 语句,我是否会处于另一个 session 中,因此不会获得 currval?
感谢您的指点。
编辑:我觉得这必须在数据库级别完成(并发问题)并发布了相应的 PostgreSQL 问题 - How can I forward a primary key sequence in PostgreSQL safely?
最佳答案
由于我还没有找到执行此操作的“自动化”方式,我正在考虑以下解决方法 - 它对我的特定情况是可行的:
- 使用 MAXVALUE 49999 NO CYCLE 设置序列
- 当达到 49999 时,下一个 save() 将遇到 postgres 错误
- 捕获该异常并作为表单错误重新引发“你的数字用完了,请重置到下一个 block 然后重试”
- 提供一个 View ,用户可以在其中激活下一个 block ,即执行“ALTER SEQUENCE my_seq RESTART WITH 70000 MAXVALUE 89999”
我对捕获异常时自动重启感到不安:
try:
instance.save()
except RunOutOfIdsException:
restart_id_sequence()
instance.save()
因为我担心两个并发的 save() 用完 id 会导致两次单独的重新启动,并随后违反唯一约束。 (与原始问题的概念基本相同)
关于django - 如何安全地转发 Django 中的主键序列?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9307896/