2010-06-05 82 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);") 
相关问题