У меня появилось много ошибок с сообщением:
"DatabaseError: current transaction is aborted, commands ignored until end of transaction block"
после изменения с python-psycopg на python-psycopg2 в качестве механизма базы данных проекта Django.
Код остается тем же, просто не знаю, откуда эти ошибки.
Это то, что postgres делает, когда запрос вызывает ошибку, и вы пытаетесь запустить другой запрос без предварительного отката транзакции. Чтобы исправить это, вы захотите выяснить, где в коде выполняется неправильный запрос. Возможно, было бы полезно использовать параметры log_statement и log_min_error_statement в ваш сервер postgresql.
Чтобы избавиться от ошибки, откат последней (ошибочной) транзакции после исправления кода:
from django.db import transaction
transaction.rollback()
Вы можете использовать try-except, чтобы предотвратить возникновение ошибки:
from django.db import transaction, DatabaseError
try:
a.save()
except DatabaseError:
transaction.rollback()
Обратитесь: Документация Django
Итак, я столкнулся с этой проблемой. Проблема, с которой я столкнулась, заключалась в том, что моя база данных не была правильно синхронизирована. Простые проблемы всегда, кажется, вызывают наибольшее беспокойство...
Чтобы синхронизировать django db из каталога приложений в терминале, введите:
$ python manage.py syncdb
Изменить: обратите внимание, что если вы используете django-south, запуск команды $python manage.py migrate также может решить эту проблему.
Счастливое кодирование!
python manage.py migrate <app>
... для всех моих приложений.
По моему опыту, эти ошибки происходят следующим образом:
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
Во втором запросе нет ничего плохого, но поскольку была обнаружена реальная ошибка, второй запрос - это тот, который вызывает (менее информативную) ошибку.
edit: это происходит только в том случае, если предложение except
ловит IntegrityError
(или любое другое исключение базы данных низкого уровня). Если вы поймаете что-то вроде DoesNotExist
, эта ошибка не появится, потому что DoesNotExist
не повреждает транзакции.
Урок здесь не делает try/except/pass.
Я думаю, что пример, который упоминает священник, скорее всего будет обычной причиной этой проблемы при использовании 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,
}
}
Я не уверен, есть ли важные соображения производительности (или любого другого типа).
Если вы получаете это в интерактивной оболочке и нуждаетесь в быстром исправлении, сделайте следующее:
from django.db import connection
connection._rollback()
изначально видел в этот ответ
У меня проблема с силимаром. Решением было мигрировать db (manage.py syncdb
или manage.py schemamigration --auto <table name>
, если вы используете юг).
Я столкнулся с аналогичным поведением при работе с неисправной транзакцией на терминале postgres
. После этого ничего не прошло, так как database
находится в состоянии error
. Однако, как быстрое решение, если вы можете позволить себе избежать rollback transaction
. Следующее сделало трюк для меня:
COMMIT;
Это очень странное поведение для меня. Я удивлен, что никто не думал о точках сохранения. В моем запросе с ошибкой кода ожидалось поведение:
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
Я считаю, что ответ @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()
в качестве извлеченного метода, если вам нужно использовать его вручную для случаев, когда требуется определенная обработка, а общая обработка декораторов недостаточна.
В ответ на @priestc и @Sebastian, что делать, если вы делаете что-то вроде этого?
try:
conn.commit()
except:
pass
cursor.execute( sql )
try:
return cursor.fetchall()
except:
conn.commit()
return None
Я просто пробовал этот код, и он, похоже, работает, не работает без каких-либо ошибок и не работает, когда запрос хорош.
У меня тоже была эта ошибка, но она маскировала еще одно релевантное сообщение об ошибке, в котором код пытался сохранить строку из 125 символов в столбце из 100 символов:
DatabaseError: value too long for type character varying(100)
Мне пришлось отлаживать код для показанного выше сообщения, в противном случае он отображает
DatabaseError: current transaction is aborted
вы можете отключить транзакцию через "set_isolation_level (0)"