DatabaseError:当前事务中止,忽略命令,直到事务块结束
我收到很多错误消息:
"DatabaseError: current transaction is aborted, commands ignored until end of transaction block"
之后从python-psycopg更改为python-psycopg2作为Django项目的数据库引擎。
代码保持不变,只是不知道这些错误来自哪里。
这是postgres在查询产生错误时所做的事情,并且您在不首先回滚事务的情况下尝试运行另一个查询。 为了解决这个问题,你需要弄清楚代码中的错误查询是在哪里执行的。 在postgresql服务器中使用log_statement和log_min_error_statement选项可能会有帮助。
为了摆脱错误,在修复代码之后回滚最后一个(错误的)事务 :
from django.db import transaction transaction.rollback()
您可以使用try-except来防止发生错误:
from django.db import transaction, DatabaseError try: a.save() except DatabaseError: transaction.rollback()
请参阅: Django文档
所以,我遇到了同样的问题。 我在这里遇到的问题是我的数据库没有正确同步。 简单的问题似乎总是引起最大的焦虑。
要在您的应用程序目录中,在terminal中同步您的django数据库,请键入:
$ python manage.py syncdb
编辑:请注意,如果您使用的是django-south,则运行“$ python manage.py migrate”命令也可能会解决此问题。
快乐的编码!
根据我的经验,这些错误就是这样发生的:
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
第二个查询没有任何问题,但是由于真正的错误被捕获,第二个查询是引发(信息量更less)错误的查询。
编辑:只有当except
子句捕获IntegrityError
(或任何其他低级别的数据库exception)时,才会发生这种情况。如果您捕获了像DoesNotExist
这样的错误,则不会出现此错误,因为DoesNotExist
不会破坏事务。
这里的教训是不要尝试/除了/通过。
我认为在使用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/ 开发/ REF /数据库/#自动提交模式
DATABASES['default'] = { #.. you usual options... 'OPTIONS': { 'autocommit': True, } }
我不确定是否有重要的性能考虑(或任何其他types)。
如果你在交互式shell中得到这个,并且需要快速修复,那么执行下面的操作:
from django.db import connection connection._rollback()
最初看到这个答案
我有silimar问题。 解决scheme是迁移数据库( manage.py syncdb
或manage.py schemamigration --auto <table name>
如果您使用南)。
我在postgres
terminal上运行有故障的事务时遇到类似的行为。 之后没有任何事情发生,因为database
处于error
状态。 但是,如果能够避免rollback transaction
,则可以快速修复。 以下为我做的伎俩:
COMMIT;
我只是有这个错误,但它掩盖了另一个更相关的错误消息代码试图存储在一个100个字符列中的125个字符的string:
DatabaseError: value too long for type character varying(100)
我不得不通过代码debugging以显示上述消息,否则显示
DatabaseError: current transaction is aborted
回应@priestc和@Sebastian,如果你做这样的事情呢?
try: conn.commit() except: pass cursor.execute( sql ) try: return cursor.fetchall() except: conn.commit() return None
我只是试了这个代码,它似乎工作,失败的沉默,而不必关心任何可能的错误,并在查询是好的时候工作。
我相信@ AnujGupta的答案是正确的。 然而,回滚本身可能引发一个你应该捕捉和处理的exception:
from django.db import transaction, DatabaseError try: a.save() except DatabaseError: try: transaction.rollback() except transaction.TransactionManagementError: # Log or handle otherwise
如果您发现您在各种save()
位置重写了此代码,则可以提取-method方法:
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()
作为一个提取的方法,以防需要特定处理的情况下手工使用它,而通用的装饰器处理是不够的。
这对我来说是非常奇怪的行为。 我很惊讶,没有人想到保存点。 在我的代码失败的查询是预期的行为:
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
你可以通过“set_isolation_level(0)”来禁用事务