4

私はピラミッド アプリケーションを開発しており、現在 sqlite から postgresql に移行中です。私は、postgresql のより制限的なトランザクション管理が私に悪い時間を与えていることを発見しました。

便利だと思うので、pyramid_tm を使用しています。私の問題のほとんどは、非同期呼び出し中に発生します。私が持っているのは、動的フォームを提供するビューです。アイデアは、データベース行に対応する ID を取得した場合、既存の行を編集することです。それ以外の場合は、新しい人を追加しています。

@view_config(route_name='contact_person_form',
         renderer='../templates/ajax/contact_person_form.pt',
         permission='view',
         request_method='POST')
def contact_person_form(request):
    try:
        contact_person_id = request.params['contact_person']
        DBSession.begin_nested()
        contact_person = DBSession.query(ContactPerson).filter(ContactPerson.id == contact_person_id).one()
        transaction.commit()
    except (NoResultFound, DataError):
        DBSession.rollback()
        contact_person = ContactPerson(name='', email='', phone='')

     return dict(contact_person=contact_person)

ネストされたトランザクションを開始する必要があるのはconfig.add_request_method(get_user, 'user', reify=True)、ビューをレンダリングするときに登録されて呼び出される遅延リクエスト メソッドだからです。

def get_user(request):
    userid = unauthenticated_userid(request)
    if userid is not None:
        user = DBSession.query(Employee).filter(Employee.id == userid).first()
        return user

トランザクションが中断され、従業員の SELECT がスキップされると不平を言います。

2 つの質問があります。

  1. ネストされたトランザクションで実行transaction.commit()しても問題ありませんか? session.begin_nested()SQLAlchemy がどこで終わり、pyramid_tm が始まるかは正確にはわかりません。セッションをコミットしようとすると、トランザクション マネージャーを使用してのみコミットできるという例外が発生します。一方、DBSession.rollback() は正常に動作します。
  2. これを次のように処理しますか

    try:
        #do something with db
    except:
        #oops, let's do something else
    

わかる?私はこれが「Pythonic」であると感じていますが、この基になるトランザクションが非 Pythonic 手段を必要とするかどうかはわかりません。

4

1 に答える 1

4

transaction.commit()コードを呼び出すとセッションがcontact_personコミットされ、コミット後にオブジェクトを使用しようとするとオブジェクトが期限切れになります。同様に、userオブジェクトがコミットの両側で触れられている場合、問題が発生します。

あなたが言ったように、例外 ( NoResultFound) がある場合、セッションは無効になります。あなたが探しているのは、トランザクションがサポートするセーブポイントですが、直接ではありませんbegin_nested。むしろ、とtransaction.savepoint()組み合わせて使用​​しDBSession.flush()てエラーを処理できます。

ここでのロジックはflush、データベースで SQL を実行し、エラーを発生させ、セーブポイントをロールバックできるようにすることです。ロールバック後、セッションは回復され、思い通りに進むことができます。まだ何もコミットされておらず、そのジョブはリクエストの最後に pyramid_tm に残されています。

try:
    sp = transaction.savepoint()
    contact_person = DBSession.query(ContactPerson)\
        .filter(ContactPerson.id == contact_person_id)\
        .one()
    DBSession.flush()
except (NoResultFound, DataError):
    sp.rollback()
    contact_person = ContactPerson(name='', email='', phone='')

return dict(contact_person=contact_person)
于 2013-05-23T14:57:12.087 に答える