2009-09-03 15 views
0

私はturbogears2アプリケーションを書いています。マルチプライマリキーテーブルにオートインクリメント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_ID』はデフォルト値を持っていない」だ:私はこのようなテーブルを持っています。私は2つの主キーを持っているので、私は注文のIDを手動で設定しなければならないようです。私の質問は、新しいIDを自動的に生成する行を挿入する方法です。

idを手動で生成すると問題が発生します。例:

maxId = DBSession.query(func.max(Order)).one()[0] 
newOrder = Order(id=maxId + 1, buyer_id=xxx) 
DBSession.add(newOrder) 

このように新しい注文を追加すると問題はないようですが、2つのリクエストでほぼ同じ時刻に実行すると問題が発生します。

要求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) 

そして、すでにテーブル内の同じIDの順序があるためかもしれないが、失敗した要求。私は例外をキャッチして再試行することができます。しかし、私は不思議に思っています、より良い方法がありますか?

は時々、idは単純な整数ではありません、我々は次のように注文IDが必要になる場合があります。これらのケースで2009-09-01

で第33注文の

2009090133標準、自動インクリメントは使用できません。だから私は選択肢がありません。だから私のもう一つの質問は、例外をキャッチし、idを持つ行を挿入しようとするよりも良い方法があるということです。

答えて

1

あなたが列定義sqlexpressionは、SQL式にすることができ

id = Column(Integer, default = sqlexpression) 

上のデフォルトを使用する必要があります。ここにはdocumentationがあります。自動インクリメントの場合は、SQL式coalesce(select max(order.id) from order,0) + 1を使用する必要があります。簡単にsqlalchemy.sql.textをインポートすると、id列は次のようになります。

id = Column(Integer, default = text("coalesce(select max(order.id) from order,0) + 1")) 
1

ご注文のバイヤーごとに連続番号を使用する場合は、1つの購入者に挿入するトランザクションをシリアル化する必要があります。他のトランザクションが完了するまで

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)) 

を2つのトランザクションがそれらの並列一つに1人の買い手の注文を挿入しようとすると、このパターンを使用して最初の行にブロックしますか:あなたは買い手行の排他ロックを取得することによってそれを行うことができます失敗する。

関連する問題