2010-06-05 83 views
181

結束命令我得到了很多與消息的錯誤:DatabaseError:當前事務被中止,忽略,直到事務塊

"DatabaseError: current transaction is aborted, commands ignored until end of transaction block" 

蟒蛇,psycopg改變到Python-psycopg2後的Django項目的數據庫引擎。

代碼保持不變,只是不知道這些錯誤來自哪裏。

+2

我很好奇你對這個問題的最終解決方案是什麼?我有這個相同的問題,但由於我的託管服務提供商不記錄查詢錯誤,迄今爲止不可能找出問題所在。 – user27478 2011-10-20 07:39:43

+2

當我使用數據庫表作爲緩存後端時,我最終跟蹤到了我的問題。 Django的bug:https://code.djangoproject.com/ticket/11569 StackOverflow討論:http://stackoverflow.com/questions/1189541/django-cache-set-causing-duplicate-key-error – user27478 2011-10-21 19:30:19

+5

僅供參考如果你是隻用psycopg2而不用django,'conn.rollback()'(其中conn是你的連接對象)將清除錯誤,所以你可以運行其他查詢 – User 2013-12-08 11:56:56

回答

128

這是postgres在查詢產生錯誤時所做的事情,並且您嘗試在不首先回滾事務的情況下運行其他查詢。爲了解決這個問題,你需要弄清楚代碼中哪個地方正在執行錯誤的查詢。在你的postgresql服務器中使用log_statementlog_min_error_statement選項可能會有幫助。

+0

問題是當我使用python-psycopg時,沒有提出這樣的錯誤。 psycopg2是否實現了與postgres對話的不同機制? – jack 2010-06-05 06:28:36

+3

與服務器交談的方法可能並不重要,但可能以前使用的版本默認爲自動提交模式,而新版本則不行。錯誤可能仍然發生,但您可能更容易錯過它。自舊版本以來,數據類型轉換或其他內容也可能發生更改。無論如何,最好的解決辦法是跟蹤錯誤的查詢,以便查看錯誤。 – 2010-06-05 07:25:22

47

所以,我遇到了同樣的問題。我在這裏遇到的問題是我的數據庫沒有正確同步。簡單的問題似乎總是造成最大的焦慮...

要同步Django的數據庫,從您的應用程序目錄中,終端類型中:

$ python manage.py syncdb 

編輯:請注意,如果您正在使用django-南,運行'$ python manage.py migrate'命令也可以解決這個問題。

編碼愉快!

+3

Upvoted表明明顯。我不會放棄這一點,因爲它可能不是所尋求的答案。 – 2011-10-28 11:17:15

+5

我修正了'python manage.py migrate '類似的方法'...對於我所有的應用程序。 – Clayton 2012-02-18 04:11:02

+3

@Clayton - 你沒有說,但我假設你使用'django-south' - 'migrate'命令沒有被構建到django中。 – 2012-04-18 03:36:53

-4

你可以通過禁用事務「set_isolation_level(0)」

28

根據我的經驗,這些錯誤的發生是這樣的:

try: 
    code_that_executes_bad_query() 
    # transaction on DB is now bad 
except: 
    pass 

# transaction on db is still bad 
code_that_executes_working_query() # raises transaction error 

這沒有什麼錯第二次查詢,但由於真正的錯誤是第二個查詢是引發(更少信息量)錯誤的查詢。

編輯:如果except子句捕獲IntegrityError(或任何其他低級別的數據庫除外),這只是發生,如果趕上像DoesNotExist這個錯誤不會來了,因爲DoesNotExist不會破壞交易。

這裏的教訓是不要嘗試/除了/通過。

16

我認爲priestc提到的模式更可能是使用PostgreSQL時這個問題的通常原因。

但是我覺得這種模式是有效的用法,我不認爲這個問題應該是一個總是避免它的理由。例如:

try: 
    profile = user.get_profile() 
except ObjectDoesNotExist: 
    profile = make_default_profile_for_user(user) 

do_something_with_profile(profile) 

如果你覺得這種模式可以,但要避免明確的事務處理代碼到處都是,那麼你可能想看看開啓自動提交模式(PostgreSQL的8.2或以上版本):https://docs.djangoproject.com/en/dev/ref/databases/#autocommit-mode

DATABASES['default'] = { 
    #.. you usual options... 
    'OPTIONS': { 
     'autocommit': True, 
    } 
} 

我不確定是否有重要的性能考慮因素(或任何其他類型)。

3

我有silimar問題。解決方案是遷移db(如果使用南方,則爲manage.py syncdbmanage.py schemamigration --auto <table name>)。

121

爲了擺脫錯誤的,回滾最後的(錯誤)交易你已經固定後您的代碼:

from django.db import transaction 
transaction.rollback() 

您可以使用嘗試 - 除了防止錯誤的發生:

from django.db import transaction, DatabaseError 
try: 
    a.save() 
except DatabaseError: 
    transaction.rollback() 

參見:Django documentation

+3

這解決了核心問題,並讓您在導致中止事務的語句後恢復。 – RichVel 2012-12-15 19:17:33

+0

這個,加上try/except。 – tomwolber 2013-04-24 01:24:22

+3

爲什麼使用'IntegrityError'而不是基類'DatabaseError'? – Jonathan 2013-11-14 12:15:39

0

我只是有這個錯誤太多,但它的掩蔽另一個更相關的錯誤消息,其中該代碼試圖一個125個字符的字符串存儲在100個字符柱:

DatabaseError: value too long for type character varying(100) 

我不得不通過對上述消息的代碼調試展現出來,否則它會顯示

DatabaseError: current transaction is aborted 
+4

*您如何做到這一點可能有用... – 2013-03-15 15:57:12

0

作爲對@priestc和@Sebastian的迴應,如果你做這樣的事情呢?

try: 
    conn.commit() 
except: 
    pass 

cursor.execute(sql) 
try: 
    return cursor.fetchall() 
except: 
    conn.commit() 
    return None 

我只是嘗試這個代碼,它似乎工作,默默失敗而不必在意任何可能的錯誤,當查詢是很好的工作。

5

如果你得到這個,而在交互shell,需要速戰速決,這樣做:

from django.db import connection 
connection._rollback() 

原本出現在this answer

0

我相信@ AnujGupta的答案是正確的。然而回滾本身可以拋出一個異常,你應該能夠捕獲並處理:

from django.db import transaction, DatabaseError 
try: 
    a.save() 
except DatabaseError: 
    try: 
     transaction.rollback() 
    except transaction.TransactionManagementError: 
     # Log or handle otherwise 

如果你發現你改寫各種save()位置的代碼,你可以提取法:

import traceback 
def try_rolling_back(): 
    try: 
     transaction.rollback() 
     log.warning('rolled back') # example handling 
    except transaction.TransactionManagementError: 
     log.exception(traceback.format_exc()) # example handling 

最後,你可以使用保護它們使用save()方法裝飾美化它:即使你實現上述裝飾

from functools import wraps 
def try_rolling_back_on_exception(fn): 
    @wraps(fn) 
    def wrapped(*args, **kwargs): 
     try: 
      return fn(*args, **kwargs) 
     except: 
      traceback.print_exc() 
      try_rolling_back() 
    return wrapped 

@try_rolling_back_on_exception 
def some_saving_method(): 
    # ... 
    model.save() 
    # ... 

,保留try_rolling_back()作爲提取方法仍然很方便,以防需要特定處理的情況下手動使用它,並且通用裝飾器處理不夠。

0

這對我來說是非常奇怪的行爲。我很驚訝沒有人想到保存點。在我的代碼失敗的查詢是預期的行爲:

from django.db import transaction 
@transaction.commit_on_success 
def update(): 
    skipped = 0 
    for old_model in OldModel.objects.all(): 
     try: 
      Model.objects.create(
       group_id=old_model.group_uuid, 
       file_id=old_model.file_uuid, 
      ) 
     except IntegrityError: 
      skipped += 1 
    return skipped 

我已經改變了代碼,這樣使用保存點:

from django.db import transaction 
@transaction.commit_on_success 
def update(): 
    skipped = 0 
    sid = transaction.savepoint() 
    for old_model in OldModel.objects.all(): 
     try: 
      Model.objects.create(
       group_id=old_model.group_uuid, 
       file_id=old_model.file_uuid, 
      ) 
     except IntegrityError: 
      skipped += 1 
      transaction.savepoint_rollback(sid) 
     else: 
      transaction.savepoint_commit(sid) 
    return skipped 
3

我遇到過類似的行爲,而postgres終端上運行中的故障交易。此後沒有任何事情發生,因爲database處於error的狀態。但是,如果您能承受,則可以快速修復,以避免rollback transaction。下面的伎倆對我來說:

COMMIT;

0

只使用回滾

示例代碼

try: 
    cur.execute("CREATE TABLE IF NOT EXISTS test2 (id serial, qa text);") 
except: 
    cur.execute("rollback") 
    cur.execute("CREATE TABLE IF NOT EXISTS test2 (id serial, qa text);") 
相關問題