2017-04-18 81 views
0

我不知道是否有可能以某種方式鎖定一些數據庫表的保護寫或類似的東西,以防止另一個應用程序在事務正在進行時修改這些?SQlalchemy數據庫級別鎖定

我現在有這樣的事情。表A,B和C,它們之間具有一對多關係A-> B和B-> C。該函數從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我總是開始一個交易與DECLARE交易...保留A,B,C FOR PROTECTED WRITE;或類似的東西。現在已經消失了,我只需要捕捉異常,或者我仍然可以從鎖定數據庫級別中受益?

哈努哈利

回答

2

您可以使用LOCK command進行明確鎖定PostgreSQL的:

LOCK A, B, C IN ACCESS EXCLUSIVE MODE; 

然而,鎖定三個表是解決問題的一個非常嚴厲的方式。既然你有一個1米的關係,你可以考慮在A鎖定該行,而不是在每個事務的開頭:

SELECT * FROM A WHERE ... FOR UPDATE; 

在SQLAlchemy中做到這一點的方法是:

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

謝謝。這是我正在尋找的。 – Hannu