我有这样的表:
class Tag(Base):
__tablename__ = 'tag'
id = Column(Integer, primary_key=True)
name = Column(Unicode(50), nullable=False)
def __init__(self, name):
self.name = name
Supose表为空。 比我以这种方式插入一些数据:
t = Tag('first tag')
t.id = 2
dbsession.add(t)
dbsession.commit()
没关系:我的postgresql表中有一行,id = 2。 下一个:
t = Tag('second tag')
dbsession.add(t)
dbsession.commit()
比我有2行:{id:1,名称:'第二个标记'}和{id:2,名称:'first_tag'}
下一步(最后一步):
t = Tag('third tag')
dbsession.add(t)
dbsession.commit()
IntegrityError :( IntegrityError)重复键值违反了唯一约束“tag_pkey”
(它想要创建id = 2的行,但它已经与第一个标签一起使用了)
是否有可能以某种方式对postgres说:如果这样的pkey存在,请尝试下一个直到它可用?
使用转储时非常有用。
提前致谢!
答案 0 :(得分:4)
我不知道有什么安全,有效的方法来做你想做的事。您应该自己选择是自己定义密钥还是使用生成的密钥并坚持使用一种策略。
如果你不介意可怕的并发性,你可以LOCK TABLE thetable
,做你的工作,setval
表的标识符序列到你插入的下一个空闲值后,commit
到释放锁。但是,这仍然会导致显式调用nextval
的应用程序(如许多ORM)的问题,而不是让数据库通过从?INSERT
列列表中省略它或明确地将其命名为{{1}来定义值}}
否则,您可以让您的代码(或PL / PgSQL帮助程序函数)在重试循环中执行插入操作,该循环会增加密钥并在获取完整性错误时再次尝试。如果您需要执行的操作不仅仅是每个事务的一个插入,那么此策略将不起作用。此外,在DEFAULT
隔离模式下,我认为你不能用PL / PgSQL来做,你必须使用客户端重试循环来处理序列化失败。
这是一个糟糕的主意。一致地使用应用程序定义的键,或者一致地使用数据库定义的键。不要混淆两者。