Использование Postgres в веб-приложении: ошибки «транзакция прервана» - PullRequest
3 голосов
/ 05 февраля 2010

Недавно я переместил веб-приложение, которое разрабатываю, из MySQL в PostgreSQL по соображениям производительности (мне нужна функциональность, которую обеспечивает PostGIS). Сейчас довольно часто встречается следующая ошибка:

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

Серверное приложение использует mod_python. Ошибка возникает в функции приветствия (то есть той, которая создает новый сеанс для этого конкретного клиента). Здесь идет соответствующий фрагмент кода (исключение происходит в строке, где вызывается 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. курсоры [экземпляр] и подключения [экземпляр] - это подключение к базе данных и курсор для экземпляра веб-приложения, обслуживаемого этим доменным именем. То есть один и тот же сервер обслуживает example1.com и example2.com и использует эти словари для вызова соответствующей базы данных в зависимости от имени сервера, к которому пришел запрос.
  2. Действительно ли мне нужно блокировать таблицы в функции hello ()?
  3. Большая часть кода в hello () необходима для поддержки одного отдельного сеанса на вкладку браузера. Я не смог найти способ использовать только файлы cookie, поскольку вкладки браузера, открывающие веб-сайт, делят пул файлов cookie. Есть ли лучший способ сделать это?

Большое спасибо.

1 Ответ

10 голосов
/ 05 февраля 2010

эта ошибка вызвана предыдущей ошибкой. посмотрите на этот кусок кода:

>>> 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()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...