2017-04-18 43 views
0

トランザクションの進行中に別のアプリケーションがこれらを変更するのを防ぐため、何らかの方法で保護された書き込みなどのデータベーステーブルをロックすることは可能でしょうか?SQlalchemyデータベースレベルのロック

私は今このようなものを持っています。表A、B、およびCは、A→BおよびB→Cの間に1対多数の関係を持つ。この関数はrabbitmqからデータを受け取り、A、Bおよび/またはC(通常はCのみ)を更新するか、または欠落している場合は新しい行を作成します。

Session=scoped_session(session_factory) 
try: 
    foo = Session.query(A).filter(....).one() 
except NoResultFound: 
    Session.remove() 
    return 

try: 
    bar = Session.query(B).filter(......).one() 
except NoResultFound: 
    bar = B(field1=x, field2=y etc.) 
    Session.add(bar) 

try: 
    xyzzy = Session.query(C).filter(...).order_by(...).limit(1).one() 
except NoResultFound: 
    xyzzy = C(.......) 
    Session.add(xyzzy) 

foo.fieldn = var1 
bar.fieldn = var2 
xyzzy.fieldn = var3 
etc. 

Session.commit() 
Session.remove() 

これはすべて正常に動作します。問題は、私は、要求に応じてクリーンアップを行う別のプログラム(全く異なるpythonスクリプト)があることです。基本的にA、B、Cのすべてを削除します。これも機能します。

私の最初のプログラムは、これに削除した直後にクラッシュ:

sqlalchemy.orm.exc.StaleDataError: UPDATE statement 
on table 'C' expected to update 1 row(s); 0 were matched. 

が、私はこの例外をキャッチし、それに応じて反応するが、私はする必要はありますか?この問題は、両方のプログラムでA、B、Cをデータベースレベルの短いファイルに予約できる場合に解決されます。これらの取引はすべて期間が短い。私はsqlalchemyの文書から、セッションもトランザクションを開始するはずであると理解していますが、明らかにこれはデータベースレベルのトランザクションとは異なるものです。起こるようです何

は私Session.query(C)は、行を見つけたが、最初のプログラムは、発行前にSession.commitが、他のプログラムがそれを()削除されたことです。

20+年前に90のデータベースとCと私は常に保護WRITE FOR A、B、Cを予約したDECLARE TRANSACTIONとの取引を開始しました...。またはそのようなものです。それは、今行って、私はちょうど例外をキャッチする必要がある、または私はまだデータベースレベルでのロックの恩恵を受けることができていますか?

ハンヌ

答えて

2

あなたがLOCK commandと明示的なロックのPostgreSQLを実行することができます。

LOCK A, B, C IN ACCESS EXCLUSIVE MODE; 

をしかし、3つのテーブルをロックすることで問題を解決するために非常に重い利き方法です。あなたは1-mの関係を持っているので、あなたは、各トランザクションの開始時に、代わりにAの行にロックを検討することができます

SELECT * FROM A WHERE ... FOR UPDATE; 

をSQLAlchemyの中でこれを行う方法は次のとおりです。

foo = Session.query(A).filter(....).with_for_update().one() 
+0

感謝。これは私が探していたものです。 – Hannu

関連する問題