DatabaseError:当前事务中止,命令被忽略,直到事务块结束?


252

消息有很多错误:

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

从python-psycopg更改为python-psycopg2作为Django项目的数据库引擎。

代码保持不变,只是不知道这些错误来自何处。


2
我很好奇,您对这个问题的最终解决方案是什么?我遇到了同样的问题,但是由于我的托管服务提供商没有记录查询错误,因此到目前为止不可能弄清楚出了什么问题。
gerdemb

2
我最终将问题归结为使用数据库表作为缓存后端时的错误。Django的错误:code.djangoproject.com/ticket/11569 StackOverflow的讨论:stackoverflow.com/questions/1189541/...
gerdemb

7
仅供参考:如果您仅使用不带Django的psycopg2,conn.rollback()(其中conn是您的连接对象)将清除错误,以便您可以运行其他查询
用户

Answers:


177

当查询产生错误并且您尝试运行另一个查询而不先回滚事务时,这就是postgres所做的。(您可能会认为这是一项安全功能,可以防止您破坏数据。)

要解决此问题,您将需要弄清楚错误查询在代码中的何处执行。在您的PostgreSQL服务器中使用log_statementlog_min_error_statement选项可能会有所帮助。


问题是当我使用python-psycopg时,没有出现此类错误。psycopg2是否实现了与postgres对话的不同机制?
杰克

4
与服务器通信的方法可能并不重要,但是您之前使用的版本可能以某种方式默认为自动提交模式,而新版本则没有。该错误可能仍然发生,但是您更容易错过它。自旧版本以来,数据类型转换或其他更改也可能会发生变化。无论如何,最好的解决方法是跟踪错误的查询,以便您可以查看问题所在。
ʇsәɹoɈ

133

要消除错误,请在修复代码后回滚上一个(错误的)事务

from django.db import transaction
transaction.rollback()

您可以使用try-except来防止发生错误:

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

参考:Django文档


3
这解决了核心问题,并让您在引起事务中止的语句之后恢复。
RichVel 2012年

这个,结合try / except。
tomwolber

3
为什么使用IntegrityError而不是基类DatabaseError
乔纳森·

由于某些原因,我不得不将回滚移到“除外”部分之外。我使用.bulk_create(),而不是.save()
NU珠峰


50

因此,我遇到了同样的问题。我在这里遇到的问题是我的数据库未正确同步。简单的问题似乎总是引起最大的忧虑。

要在终端的应用程序目录中同步django db,请输入:

$ python manage.py syncdb

编辑:请注意,如果您使用的是django-south,则运行'$ python manage.py migration'命令也可以解决此问题。

祝您编码愉快!


3
为表述明显而投票。我不会给予多于一次的投票,因为这可能不是寻求的答案。
詹姆森·奎因

5
我通过python manage.py migrate <app>...为所有应用程序修复了类似问题。
克莱顿

3
@Clayton-您没有说,但我想您正在使用django-south -该migrate命令未内置于Django中。
格雷格·鲍尔

@ GregBall-没错,我正在使用django-south。抱歉,未指定。
克莱顿2012年

在执行syncdb时出现此错误-我认为这与django遍历表的顺序有关。
斯图尔特·阿克森


34

以我的经验,这些错误是通过以下方式发生的:

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

我认为使用PostgreSQL时,priestc提到的模式更可能是此问题的常见原因。

但是,我认为该模式有有效的用途,我不认为这个问题应该成为始终避免它的原因。例如:

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,
    }
}

我不确定是否有重要的性能考虑因素(或任何其他类型的考虑因素)。


6

如果您在交互式外壳程序中得到此消息并需要快速修复,请执行以下操作:

from django.db import connection
connection._rollback()

最初在此答案中看到


6

postgres终端上运行有故障的事务时,我遇到了类似的行为。此后什么都没有发生,因为database处于的状态error。但是,如果可以避免的话,只是快速解决方法rollback transaction。以下对我有用:

COMMIT;


我在一个代表,这正是我在寻找的答案。
收缩


5

只是使用回滚

范例程式码

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);")

1

我也刚遇到这个错误,但是它掩盖了另一个更相关的错误消息,其中代码试图将125个字符的字符串存储在100个字符的列中:

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

我必须调试代码才能显示以上消息,否则它将显示

DatabaseError: current transaction is aborted

1

作为对@priestc和@Sebastian的回应,如果您做这样的事情怎么办?

try:
    conn.commit()
except:
    pass

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

我只是尝试了这段代码,它似乎可以正常工作,无需关心任何可能的错误就可以静默失败,并且在查询良好时可以正常工作。


1

我相信@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()在需要进行特殊处理而通用装饰器处理还不够的情况下,如果需要手动使用提取方法,将其保留为提取方法仍然很方便。


1

这对我来说是非常奇怪的行为。我很惊讶没有人想到保存点。在我的代码中,查询失败是预期的行为:

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

1

在Flask Shell中,我需要做的只是session.rollback()克服这个问题。


1

我已经遇到了这个问题,由于错误交易尚未正确结束,因此出现错误,我在这里找到了postgresql_transactionsTransaction Control命令

交易控制

以下命令用于控制交易

BEGIN TRANSACTION  To start a transaction.

COMMIT  To save the changes, alternatively you can use END TRANSACTION command.

ROLLBACK  To rollback the changes.

所以我使用END TRANSACTION来结束错误TRANSACTION,如下代码:

    for key_of_attribute, command in sql_command.items():
        cursor = connection.cursor()
        g_logger.info("execute command :%s" % (command))
        try:
            cursor.execute(command)
            rows = cursor.fetchall()
            g_logger.info("the command:%s result is :%s" % (command, rows))
            result_list[key_of_attribute] = rows
            g_logger.info("result_list is :%s" % (result_list))
        except Exception as e:
            cursor.execute('END TRANSACTION;')
            g_logger.info("error command :%s and error is :%s" % (command, e))
    return result_list

-6

您可以通过“ set_isolation_level(0)”禁用交易

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.