pyplot - plot python




DatabaseError: la transaction en cours est annulée, les commandes ignorées jusqu'à la fin du bloc de transaction (10)

J'ai eu beaucoup d'erreurs avec le message:

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

est passé de python-psycopg à python-psycopg2 en tant que moteur de base de données du projet Django.

Le code reste le même, ne sais pas d'où viennent ces erreurs.


C'est ce que postgres fait quand une requête produit une erreur et que vous essayez d'exécuter une autre requête sans d'abord annuler la transaction. Pour le réparer, vous aurez besoin de savoir où dans le code cette requête est en cours d'exécution. Il peut être utile d'utiliser les options log_statement et log_min_error_statement dans votre serveur postgresql.


C'est un comportement très étrange pour moi. Je suis surpris que personne n'ait pensé aux points de sauvegarde. Dans mon code, l'échec de la requête était le comportement attendu:

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

J'ai changé le code de cette manière pour utiliser les points de sauvegarde:

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

Dans mon expérience, ces erreurs se produisent de cette façon:

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

Il n'y a rien de mal avec la deuxième requête, mais puisque l'erreur réelle a été interceptée, la deuxième requête est celle qui soulève l'erreur (beaucoup moins informative).

edit: cela se produit uniquement si la clause except capture IntegrityError (ou toute autre exception de base de données de bas niveau). Si vous interceptez quelque chose comme DoesNotExist cette erreur ne s'affichera pas, car DoesNotExist ne corrompt pas la transaction.

La leçon ici est de ne pas essayer / sauf / passer.


Donc, j'ai rencontré ce même problème. Le problème que j'avais ici était que ma base de données n'était pas correctement synchronisée. Les problèmes simples semblent toujours causer le plus d'angoisse ...

Pour synchroniser votre django db, depuis le répertoire de votre application, dans le terminal, tapez:

$ python manage.py syncdb

Edit: Notez que si vous utilisez django-south, l'exécution de la commande '$ python manage.py migrate' peut également résoudre ce problème.

Codage heureux!


J'ai juste eu cette erreur aussi mais il masquait un autre message d'erreur plus pertinent où le code essayait de stocker une chaîne de 125 caractères dans une colonne de 100 caractères:

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

J'ai dû déboguer à travers le code pour que le message ci-dessus apparaisse, sinon il affiche

DatabaseError: current transaction is aborted

J'ai le problème de silimar. La solution consistait à migrer db ( manage.py syncdb ou manage.py schemamigration --auto <table name> si vous utilisez sud).


Je crois que la réponse de @ AnujGupta est correcte. Cependant, le rollback peut lui-même déclencher une exception que vous devriez attraper et gérer:

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

Si vous trouvez que vous réécrivez ce code dans divers emplacements save() , vous pouvez extraire la méthode:

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

Enfin, vous pouvez l'utiliser à l'aide d'un décorateur qui protège les méthodes utilisant 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()
    # ...

Même si vous implémentez le décorateur ci-dessus, il est toujours pratique de conserver try_rolling_back() comme méthode extraite au cas où vous auriez besoin de l'utiliser manuellement pour les cas où une manipulation spécifique est requise, et la gestion générique du décorateur n'est pas suffisante.


Je pense que le modèle priestc mentionne plus de chances d'être la cause habituelle de ce problème lors de l'utilisation de PostgreSQL.

Cependant, je pense qu'il y a des utilisations valables pour le modèle et je ne pense pas que cette question devrait être une raison pour toujours l'éviter. Par exemple:

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

do_something_with_profile(profile)

Si vous vous sentez bien avec ce modèle, mais que vous voulez éviter le code de traitement des transactions explicite, alors vous pouvez vous intéresser au mode autocommit (PostgreSQL 8.2+): https://docs.djangoproject.com/en/dev/ref/databases/#autocommit-mode

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

Je ne suis pas sûr s'il y a des considérations de performance importantes (ou de tout autre type).


Si vous obtenez ceci dans un shell interactif et que vous avez besoin d'une solution rapide, procédez comme suit:

from django.db import connection
connection._rollback()

à l'origine vu dans cette réponse


il suffit d'utiliser rollback

Exemple de code

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