2010-02-05 78 views
3

爲了性能方面的原因(我需要PostGIS提供的功能),最近我將一個Web應用程序從MySQL發展到PostgreSQL。現在經常遇到以下錯誤:在Web應用程序中使用Postgres:「交易中止」錯誤

current transaction is aborted, commands ignored until end of transaction block

服務器應用程序使用mod_python的。該錯誤發生在hailing函數中(即爲此特定客戶端創建新會話的錯誤)。這裏去相應的代碼(在哪裏sessionAppId調用該行出現異常:

def hello(req): 
req.content_type = "text/json" 
req.headers_out.add('Cache-Control', "no-store, no-cache, must-revalidate") 
req.headers_out.add('Pragma', "no-cache") 
req.headers_out.add('Expires', "-1") 
instance = req.hostname.split(".")[0] 

cookieSecret = '....' # whatever :-) 
receivedCookies = Cookie.get_cookies(req, Cookie.SignedCookie, secret = cookieSecret) 
sessionList = receivedCookies.get('sessions', None) 
sessionId = str(uuid.uuid4()) 
if sessionList: 
    if type(sessionList) is not Cookie.SignedCookie: 
     return "{status: 'error', errno:1, errmsg:'Permission denied.'}" 
    else: 
     sessionList = sessionList.value.split(",") 
     for x in sessionList[:]: 
      revisionCookie = receivedCookies.get('rev_' + str(sessionAppId(x, instance)), None) 
      # more processing here.... 
# ..... 
cursors[instance].execute("lock revision, app, timeout IN SHARE MODE") 
cursors[instance].execute("insert into app (type, active, active_revision, contents, z) values ('session', true, %s, %s, 0) returning id", (cRevision, sessionId)) 
sAppId = cursors[instance].fetchone()[0] 
cursors[instance].execute("insert into revision (app_id, type) values (%s, 'active')", (sAppId,)) 
cursors[instance].execute("insert into timeout (app_id, last_seen) values (%s, now())", (sAppId,)) 
connections[instance].commit() 
# ..... 

這裏是sessionAppId本身:

def sessionAppId(sessionId, instance): 
cursors[instance].execute("select id from app where type='session' and contents = %s", (sessionId,)) 
row = cursors[instance].fetchone() 
if row == None: 
    return 0 
else: 
    return row[0] 

一些澄清和其他問題:

  1. 遊標[實例]和連接[實例]是服務於此域名的Web應用程序實例的數據庫連接和遊標,即同一服務器服務於example1.com和example2.com, d使用這些字典根據請求的服務器名稱調用適當的數據庫。
  2. 我真的需要鎖定hello()函數中的表嗎?
  3. hello()中的大部分代碼需要爲每個瀏覽器選項卡維護一個單獨的會話。我無法找到一種方法來處理cookie,因爲打開網站的瀏覽器標籤共享Cookie池。有沒有更好的方法來做到這一點?

非常感謝。

回答

10

該錯誤是由於先例錯誤而導致的。看看這段代碼:

>>> import psycopg2 
>>> conn = psycopg2.connect('') 
>>> cur = conn.cursor() 
>>> cur.execute('select current _date') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
psycopg2.ProgrammingError: syntax error at or near "_date" 
LINE 1: select current _date 
        ^

>>> cur.execute('select current_date') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
psycopg2.InternalError: current transaction is aborted, commands ignored until end of transaction block 

>>> conn.rollback() 
>>> cur.execute('select current_date') 
>>> cur.fetchall() 
[(datetime.date(2010, 2, 5),)] 
>>> 

如果您熟悉扭曲,看twisted.enterprise.adbapi爲例如何處理遊標。基本上你應該總是提交或回滾你的遊標:

try: 
    cur.execute("...") 
    cur.fetchall() 
    cur.close() 
    connection.commit() 
except: 
    connection.rollback() 
+0

感謝您的提示。我現在將修復我的代碼並查看是否有幫助 – dpq 2010-02-05 18:31:03

+0

到目前爲止,正確提交和回滾所有操作(包括僅涉及從表中選擇的操作)已消除了此問題。謝謝! – dpq 2010-02-05 18:49:01