2009-09-18 89 views
1

比方說,我有app1.models.ModelOne定義與保存裝飾用@commit_on_success。在ModelOne.save()中捕獲的所有異常都被重新提出。適用於model_one_instance.save()django中的嵌套事務?

但是,在app2我需要進行一系列的插入到ModelOne和回滾所有他們,如果他們中的任何一個失敗。我該如何做到這一點?

裝飾app2.jobs.do_the_inserts@commit_on_success不按預期方式工作。

回答

3

嵌套事務是數據庫特定的,所以你將失去可移植性。如果你需要,我會考慮做的是改變一些更靈活的簡單@commit_on_save:

def save(commit=True): 
    if commit: 
    db.start_transaction() 
    try: 
     self.real_save() 
     db.commit_transaction() 
    except backend.DatabaseError, e: 
     db.rollback_transaction() 
     raise e 
    else: 
    self.real_save()  

否則,您可以運行任意的SQL命令,所以你可以調用db.connection.cursor().execute()與任何後端數據庫使用,可能一個檢查不會爲其他後端做任何事情,所以你仍然可以使用sqlite進行本地測試。

根據您的應用程序結構,它也可能使用savepoints。我已經寫了幾公用事業裏面做這樣的事情:

  • 開始交易
  • 執行強制性命令
  • 開始可選聲明:
    • 開始保存點
    • 執行
    • 保存點承諾或回滾
  • 更強制性SQL
  • 承諾
+1

我認爲你的解決方案正在解決一個不同的問題。假設你有兩個方法,例如foo()和bar(),並且都使用@commit_on_success進行裝飾。如果foo()調用bar(),你希望django什麼時候發送COMMIT到數據庫? 我認爲直觀的答案是,django在foo()方法的末尾發出一個COMMIT。然而,Django發送兩個COMMIT,一個在bar()的末尾,另一個在foo()的末尾。這樣做的結果是事務修飾器永遠不能嵌套或者會發生非常糟糕的事情。 –

+0

並非真正的「特定於數據庫」,嵌套事務通過'SAVEPOINT/ROLLBACK TO SAVEPOINT/RELEASE SAVEPOINT'命令在所有主要數據庫中都可用 - 這些命令似乎在PostgreSQL,SQLite和MySQL中的工作方式相同。 – intgr

+0

在Django中,1.4之前不支持保存點(請注意,原文是在2009年)。即使如此,你仍然有通常的InnoDB/MyISAM的爭論 - 這並不是說你不應該使用該功能,但更多的是開發人員應該考慮如果支持未啓用應該怎麼做。 –

0

根據您的DBMS服務器嵌套事務可能根本不支持。在DBMS中恰當地實現嵌套事務實際上是相當困難的,因爲你最終不得不在事務之間共享鎖。

但是,您所描述的內容聽起來不像嵌套事務。我不知道django是否支持XA事務,但是您所描述的可以通過TP監視器體系結構和XA意識DBMS(現在大多數是這些日期)來實現。

如果您的平臺不支持XA事務,則必須構建事務處理,以便如何將它們回滾的記錄存儲在某處。福勒公司的企業應用架構模式中描述的「工作單元」模式可能爲此類子系統的體系結構提供了良好的開端。

+0

DBMS是第8.3頁; 我想知道是否有辦法通過ORM層做到這一點。 – ohnoes

+0

PG 8.3支持XA事務,但我不知道Django是否支持它們。這個鏈接的文章進入django的事務管理http://blogs.gnome.org/jamesh/2008/09/01/transaction-management-in-django/ – ConcernedOfTunbridgeWells