2015-04-14 77 views
14

我們一直在試驗sqlalchemy的斷開連接處理,以及它如何與ORM集成。我們已經研究了這些文檔,並且建議似乎是要抓住斷開連接異常,發出rollback()並重試代碼。更好的方法來處理sqlalchemy斷開連接

如:

import sqlalchemy as SA 

retry = 2 
while retry: 
    retry -= 1 
    try: 
     for name in session.query(Names): 
      print name 
     break 
    except SA.exc.DBAPIError as exc: 
     if retry and exc.connection_invalidated: 
      session.rollback() 
     else: 
      raise 

我遵循的基本原理 - 你必須立即回滾任何活動的事務並對其進行重放,以確保你的行動一致的排序。

但是 - 這意味着很多額外的代碼被添加到每個想要使用數據的函數中。此外,在SELECT的情況下,我們沒有修改數據,回滾/重新請求的概念不僅不美觀,而且違反了DRY原則(不要重複自己)。

我想知道如果別人會介意分享他們如何處理與sqlalchemy斷開連接。

FYI:我們使用的SQLAlchemy 0.9.8和Postgres 9.2.9

+1

目前我們正在使用[悲觀斷開連接處理](http://docs.sqlalchemy.org/en/latest/core/pooling.html#disconnect-handling-pessimistic)和* some *成功來減輕MySQL的負擔走了'。儘管我們似乎無法從這種情況中恢復過來,但我們仍然看到一個生產案例,並且該事務無法回滾並卡住。雖然這可能與我們加入兩個事務(ZODB和SQL)並且未使用[Two-Phase commitits](兩階段提交)有關(http://docs.sqlalchemy.org/en/latest/orm/ session_transaction.html#啓用 - 兩階段提交)。 –

+0

使用PostgreSQL,我們根本沒有任何斷開連接,所以沒有經驗。 –

+0

所以 - 你決定接受try/catch/retry邏輯?我們在ORM類中有幾十個查詢函數,我們管理幾十個類。這真的加起來。順便說一句 - 我們在Postgres重啓之前一直沒有遇到任何麻煩,直到最近RHEL殺手殺死了一個長期運行的postmaster。突然意識到我們需要從優雅中恢復過來。 – user590028

回答

6

我想辦法,這是發生在一個lambda或關閉我所有的數據庫代碼,並將其傳遞到一個輔助函數的方式,將處理捕獲斷開異常並重試。

所以你的榜樣:

import sqlalchemy as SA 

def main(): 
    def query(): 
     for name in session.query(Names): 
      print name 

    run_query(query) 

def run_query(f, attempts=2): 
    while attempts > 0: 
     attempts -= 1 
     try: 
      return f() # "break" if query was successful and return any results 
     except SA.exc.DBAPIError as exc: 
      if attempts > 0 and exc.connection_invalidated: 
       session.rollback() 
      else: 
       raise 

你可以讓這個更看中的通過傳遞一個布爾到run_query處理的情況下,如果只在做一讀,因此想不回滾到重試。

這可以幫助您滿足DRY原則,因爲用於管理重試+回滾的所有難看的鍋爐代碼都放置在一個位置。

+0

這是一個很好的解決方案!感謝分享。 – user590028

+0

這是一個很好的解決方案,但現在我正在深入研究SQL Alchemy文檔,看看它是否可以自動應用於每個查詢,而不必將它傳遞到run_query。 – Mark