31 votes

Le bloc géré par la transaction est terminé avec un COMMIT/ROLLBACK en attente.

J'ai une fonction de visualisation :

@transaction.commit_manually
def xyz(request):
    if ABC:
        success = something()

        if success:
            status = "success"
            transaction.commit()

        else:
            status = "dataerrors"
            transaction.rollback()
    else:
        status = "uploadproblem"
        transaction.rollback()

    return render(request, "template.html", {
        'status': status,
    })

Je pense que chaque chemin de code termine la transaction d'une manière ou d'une autre. Mais Django semble se plaindre qu'il ne le fait pas. Une idée ?

Django Version:     1.3
Exception Type:     TransactionManagementError
Exception Value:    Transaction managed block ended with pending COMMIT/ROLLBACK

EDIT : Aucune autre exception n'est levée pour modifier le chemin du code.

0 votes

Utilisez-vous postgres ? Ces informations peuvent être pertinentes : aquí y aquí

1 votes

Oui, ABC est défini comme désolé. Nettoyage des sources trop enthousiaste !

86voto

Gert Steyn Points 1455

Après avoir rencontré un problème similaire et perdu des heures à le résoudre, j'ai compris comment déboguer cette situation.

Pour une raison quelconque, le décorateur @transaction.commit_manually fait taire les exceptions qui se produisent dans la fonction.

Retirez temporairement le décorateur de votre fonction, vous verrez maintenant l'exception, corrigez-la et remettez le décorateur en place !

1 votes

Le décorateur @transaction.commit_manually était en train de manger le vrai problème.

0 votes

Vous m'avez également permis d'économiser de nombreuses heures. Ce comportement est très étrange. J'utilise le décorateur commit_on_success et il ne se comporte pas de la même manière.

0 votes

Ce qui est étrange, c'est qu'en faisant un 1/0, on obtient une exception correcte :(

9voto

Cerin Points 9851

J'ai eu le même problème. La seule solution que j'ai trouvée a été d'utiliser une clause try/finally pour s'assurer qu'un commit se produise après le rendu.

@transaction.commit_manually
def xyz(request):
    committed = False
    try:
        if ABC:
            success = something()

            if success:
                status = "success"
                transaction.commit()
                committed = True

            else:
                status = "dataerrors"
                transaction.rollback()
                committed = True
        else:
            status = "uploadproblem"
            transaction.rollback()
            committed = True

        return render(request, "template.html", {
            'status': status,
        })
    finally:
        if not committed:
            transaction.rollback() # or .commit() depending on your error-handling logic

Cela n'a aucun sens, mais cela a fonctionné pour moi.

0 votes

Cela a fonctionné pour moi. Par ailleurs, j'ai constaté que si je voulais revenir en arrière dans le cadre d'un flux normal (et non d'une exception), je devais créer une exception (x = 1/0) pour m'assurer que je me retrouvais dans un finally avec un retour en arrière. Peut-être parce que toute ma fonction est dans un try catch.

3 votes

C'est une bonne solution, mais au lieu d'utiliser la variable commited vous pouvez utiliser transaction.is_dirty() . si vous le pouvez, vérifiez le middleware de transaction de django, il fait exactement la même chose.

2voto

srj Points 399

Une autre raison pour laquelle vous pouvez rencontrer ce problème est lorsque vous avez plusieurs bases de données dans le système.

J'ai pu surmonter cette erreur avec

@transaction.commit_manually(using='my_other_db')
def foo():
   try:
        <db query>
        transaction.commit(using='my_other_db')
   except:
        transaction.rollback(using='my_other_db')

1voto

Rob Points 78

Cela se produit toujours lorsqu'une exception non gérée se produit quelque part dans le code. Dans mon cas, pour une raison ou une autre, l'exception n'a pas été transmise au débogueur, ce qui a été à l'origine de ma confusion.

0 votes

C'est ce que je soupçonne. Mais s'il y a une exception, je ne peux pas la voir, et j'ai essayé ! Finalement, j'ai décidé de résoudre le problème d'une manière différente des transactions, et avec ma nouvelle approche, je ne vois pas l'exception que je m'attendais à voir.

1voto

Griffosx Points 140

J'ai eu un problème similaire, peut-être que ce code fonctionne pour vous :

@transaction.commit_on_success
def xyz(request):
    if ABC:
        success = something()

        if success:
            status = "success"

        else:
            status = "dataerrors"
            transaction.rollback()
    else:
        status = "uploadproblem"
        transaction.rollback()

    return render(request, "template.html", {
        'status': status,
    })

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X