Python 如何在多主键表中插入具有自动增量id的行?
我正在写一个turbogears2应用程序。我有一张这样的桌子:Python 如何在多主键表中插入具有自动增量id的行?,python,sql,database,sqlalchemy,Python,Sql,Database,Sqlalchemy,我正在写一个turbogears2应用程序。我有一张这样的桌子: class Order(DeclarativeBase): __tablename__ = 'order' # id of order id = Column(Integer, autoincrement=True, primary_key=True) # buyer's id buyer_id = Column(Integer, ForeignKey('user.user_id',
class Order(DeclarativeBase):
__tablename__ = 'order'
# id of order
id = Column(Integer, autoincrement=True, primary_key=True)
# buyer's id
buyer_id = Column(Integer, ForeignKey('user.user_id',
onupdate="CASCADE", ondelete="CASCADE"), primary_key=True)
我想在此表中插入新行,但得到的字段“order\u id”没有默认值错误。似乎我必须手动设置订单的id,因为我有两个主键。我的问题是,如何插入自动生成新ID的行
如果我手动生成id,我会遇到一些问题。例如:
maxId = DBSession.query(func.max(Order)).one()[0]
newOrder = Order(id=maxId + 1, buyer_id=xxx)
DBSession.add(newOrder)
以这种方式添加一个新订单似乎是可以的,但是,如果两个请求几乎同时运行这些代码,我们就会遇到一些问题
如果有请求a和b,请按以下顺序运行此代码:
a.maxId = DBSession.query(func.max(Order)).one()[0]
b.maxId = DBSession.query(func.max(Order)).one()[0]
b.newOrder = Order(id=maxId + 1, buyer_id=xxx)
b.DBSession.add(newOrder)
a.newOrder = Order(id=maxId + 1, buyer_id=xxx)
a.DBSession.add(newOrder)
然后请求a可能失败,因为表中已经有一个具有相同id的订单。我可以捕获异常并重试。但我想知道,有没有更好的办法
有时,id不是简单的整数,我们可能需要这样的订单id:
class Order(DeclarativeBase):
__tablename__ = 'order'
# id of order
id = Column(Integer, autoincrement=True, primary_key=True)
# buyer's id
buyer_id = Column(Integer, ForeignKey('user.user_id',
onupdate="CASCADE", ondelete="CASCADE"), primary_key=True)
2009年9月1日第33次订单的20090133标准
在这种情况下,“自动增量”不可用。所以我别无选择,手动为订单分配id。所以我的另一个问题是,除了捕获异常并重试插入id为的行之外,还有什么更好的方法吗?如果您希望订单中每个买家都有序列号,那么您必须将插入到一个买家的事务序列化。您可以通过在买方行上获取独占锁来实现这一点:
sess.query(Buyer.id).with_lockmode('update').get(xxx)
order_id = sess.query(func.max(Order.id)+1).filter_by(buyer_id=xxx).scalar() or 1
sess.add(Order(id=order_id, buyer_id=xxx))
当两个交易试图并行插入一个买家的订单时,使用此模式,其中一个交易将在第一行阻塞,直到另一个交易完成或失败。您应该在列定义中使用默认值
id = Column(Integer, default = sqlexpression)
其中sqlexpression可以是sql表达式。这是你的电话号码。对于自动增量,应使用sql表达式coalesceselect maxorder.id from order,0+1。为了方便起见,您可以导入sqlalchemy.sql.text,以便id列看起来像
id = Column(Integer, default = text("coalesce(select max(order.id) from order,0) + 1"))