web-dev-qa-db-de.com

DatabaseError: aktuelle Transaktion wird abgebrochen, Befehle werden bis zum Ende des Transaktionsblocks ignoriert

Ich habe viele Fehler mit der Nachricht erhalten:

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

nach dem Wechsel von python-psycopg zu python-psycopg2 als Datenbank-Engine des Django-Projekts.

Der Code bleibt derselbe, weiß nur nicht, woher diese Fehler kommen.

216
jack

Dies ist, was postgres tut, wenn eine Abfrage einen Fehler erzeugt und Sie versuchen, eine andere Abfrage auszuführen, ohne die Transaktion vorher rückgängig zu machen. (Sie können es als Sicherheitsfunktion betrachten, um Ihre Daten nicht zu beschädigen.)

Um dies zu beheben, sollten Sie herausfinden, wo im Code die fehlerhafte Abfrage ausgeführt wird. Es kann hilfreich sein, die Optionen log_statement und log_min_error_statement in Ihrem Postgresql-Server zu verwenden.

151
ʇsәɹoɈ

Um den Fehler zu beseitigen, rollen Sie die letzte (fehlerhafte) Transaktion zurück, nachdem Sie Ihren Code repariert haben:

from Django.db import transaction
transaction.rollback()

Sie können try-except verwenden, um das Auftreten des Fehlers zu verhindern:

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

Siehe: Django-Dokumentation

127
Anuj Gupta

Also bin ich auf dasselbe Thema gestoßen. Das Problem, das ich hier hatte, war, dass meine Datenbank nicht richtig synchronisiert wurde. Einfache Probleme scheinen immer die meisten Sorgen zu verursachen ...

Um Ihre Django-Datenbank in Ihrem App-Verzeichnis und im Terminal zu synchronisieren, geben Sie Folgendes ein:

$ python manage.py syncdb

Bearbeiten: Beachten Sie, dass das Problem mit dem Befehl "$ python manage.py migrate" gelöst werden kann, wenn Sie Django-south verwenden.

Viel Spaß beim Codieren!

50

Nach meiner Erfahrung passieren diese Fehler auf diese Weise:

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

An der zweiten Abfrage ist nichts falsch, aber da der echte Fehler abgefangen wurde, führt die zweite Abfrage zu dem (viel weniger informativen) Fehler.

edit: Dies geschieht nur, wenn die except-Klausel IntegrityError (oder eine andere einfache Datenbankausnahme) abfängt. Wenn Sie etwas wie DoesNotExist abfangen, wird dieser Fehler nicht angezeigt, da DoesNotExist die Transaktion nicht beschädigt.

Die Lektion hier ist nicht versuchen/außer/pass.

30
priestc

Ich denke, dass die priesterlichen Muster-Erwähnungen bei der Verwendung von PostgreSQL eher die übliche Ursache für dieses Problem sind.

Ich denke jedoch, dass es gültige Verwendungen für das Muster gibt, und ich denke nicht, dass dieses Problem ein Grund sein sollte, es immer zu vermeiden. Zum Beispiel:

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

do_something_with_profile(profile)

Wenn Sie mit diesem Muster zufrieden sind, aber expliziten Code für die Transaktionsverarbeitung überall vermeiden möchten, sollten Sie den Autocommit-Modus (PostgreSQL 8.2+) aktivieren: https://docs.djangoproject.com/ de/dev/ref/database/# Autocommit-Modus

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

Ich bin nicht sicher, ob es wichtige Überlegungen zur Leistung gibt (oder von einer anderen Art).

16
Sebastian

In Flask musst du nur schreiben:

curs = conn.cursor()
curs.execute("ROLLBACK")
conn.commit()

P.S. Die Dokumentation geht hier https://www.postgresql.org/docs/9.4/static/sql-rollback.html

13

Wenn Sie dies in der interaktiven Shell erhalten und eine schnelle Lösung benötigen, führen Sie folgende Schritte aus:

from Django.db import connection
connection._rollback()

ursprünglich gesehen in diese Antwort

6
tutuDajuju

Ich habe ein ähnliches Verhalten festgestellt, als ich eine fehlgeschlagene Transaktion im Terminal postgres ausgeführt habe. Danach wurde nichts durchlaufen, da sich database im Status error befindet. Allerdings nur als schnelle Lösung, wenn Sie es sich leisten können, rollback transaction zu vermeiden. Folgendes hat den Trick für mich gemacht:

COMMIT;

6
faizanjehangir

Ich habe das Silimar-Problem. Die Lösung bestand darin, db zu migrieren (manage.py syncdb oder manage.py schemamigration --auto <table name>, wenn Sie Süd verwenden).

4
Daniil Ryzhkov

Was würden Sie tun, wenn Sie auf @priestc und @Sebastian so etwas tun?

try:
    conn.commit()
except:
    pass

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

Ich habe diesen Code gerade ausprobiert, und er scheint zu funktionieren, scheitert im Hintergrund, ohne sich um mögliche Fehler kümmern zu müssen, und funktioniert, wenn die Abfrage gut ist.

1
Nate

Ich hatte auch gerade diesen Fehler, aber es maskierte eine andere, relevantere Fehlermeldung, in der der Code versuchte, eine Zeichenfolge mit 125 Zeichen in einer Spalte mit 100 Zeichen zu speichern:

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

Ich musste den Code debuggen, damit die obige Meldung angezeigt wird, andernfalls wird sie angezeigt

DatabaseError: current transaction is aborted
1
Thierry Lam

verwenden Sie einfach ein Rollback

Beispielcode

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
Umer

Ich glaube, @ AnujGuptas Antwort ist richtig. Das Rollback kann jedoch selbst eine Ausnahme auslösen, die Sie abfangen und behandeln sollten:

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

Wenn Sie feststellen, dass Sie diesen Code an verschiedenen save()-Speicherorten neu schreiben, können Sie die Methode extrahieren:

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

Schließlich können Sie es mit einem Dekorationsprogramm verbessern, das Methoden schützt, die save() verwenden:

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()
    # ...

Selbst wenn Sie den Dekorator oben implementieren, ist es dennoch praktisch, try_rolling_back() als extrahierte Methode beizubehalten, falls Sie ihn manuell verwenden müssen, wenn eine bestimmte Behandlung erforderlich ist und die generische Handhabung des Dekorators nicht ausreicht.

1
Jonathan

Dies ist ein sehr seltsames Verhalten für mich. Ich bin überrascht, dass niemand an Sicherheitspunkte dachte. In meinem Code fehlgeschlagene Abfrage war erwartetes Verhalten:

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

Ich habe den Code auf diese Weise geändert, um Sicherungspunkte zu verwenden:

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
homm

Ich bin auf dieses Problem gestoßen, der Fehler tritt auf, da die Fehlertransaktionen nicht ordnungsgemäß beendet wurden. Ich habe den Befehl postgresql_transactions des Transaktionssteuerungsbefehls hier gefunden

Transaktionskontrolle

Die folgenden Befehle dienen zur Steuerung von Transaktionen

BEGIN TRANSACTION − To start a transaction.

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

ROLLBACK − To rollback the changes.

also benutze ich den END TRANSACTION, um den Fehler TRANSACTION zu beenden, Code wie folgt:

    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
0
Dean Fang

In Flask Shell brauchte ich nur eine session.rollback(), um an dieser Stelle vorbeizukommen.

0
watsonic