Django 1.6 propose @transaction.atomic
dans le cadre de la refonte de la gestion des transactions à partir du 1.5.
J'ai une fonction qui est appelée par une commande de gestion Django qui est à son tour appelée par cron, c'est-à-dire aucune requête HTTP déclenchant des transactions dans ce cas.
from Django.db import transaction
@transaction.commit_on_success
def my_function():
# code here
Dans le bloc de code ci-dessus commit_on_success
utilise une seule transaction pour tout le travail effectué dans my_function
.
Remplace @transaction.commit_on_success
avec @transaction.atomic
entraîne le même comportement? @transaction.atomic
état des documents :
L'atomicité est la propriété qui définit les transactions de base de données. atomic nous permet de créer un bloc de code au sein duquel l'atomicité sur la base de données est garantie. Si le bloc de code est terminé avec succès, les modifications sont validées dans la base de données. S'il existe une exception, les modifications sont annulées.
Je suppose qu'ils entraînent le même comportement; correct?
Oui. Vous devez utiliser atomic
aux endroits où vous avez déjà utilisé commit_on_success
.
Étant donné que le nouveau système de transactions est conçu pour être plus robuste et cohérent, il est possible que vous puissiez voir un comportement différent. Par exemple, si vous détectez des erreurs de base de données et essayez de continuer, vous verrez un TransactionManagementError
, alors que le comportement précédent n'était pas défini et dépendait probablement de la casse.
Mais si vous faites les choses correctement, tout devrait continuer de fonctionner de la même manière.
Sur la base de la documentation que j'ai lue sur le sujet, il y a une différence significative lorsque ces décorateurs sont imbriqués.
L'imbrication de deux blocs atomic
ne fonctionne pas de la même manière que l'imbrication de deux blocs commit_on_success
blocs.
Le problème est qu'il y a deux garanties que vous voudriez avoir de ces blocs.
Il est impossible de fournir les deux garanties lorsque les blocs sont imbriqués. Si une exception est levée après avoir quitté le bloc le plus à l'intérieur mais avant de quitter le bloc le plus à l'extérieur, vous devrez échouer de l'une des deux manières suivantes:
Voici où vous trouvez la différence. En utilisant commit_on_success
donnerait une durabilité pour le bloc le plus à l'intérieur, mais aucune atomicité pour le bloc le plus à l'extérieur. L'utilisation de atomic
donnerait une atomicité pour le bloc le plus à l'extérieur, mais aucune durabilité pour le bloc le plus à l'intérieur.
Le simple fait de lever une exception en cas d'imbrication pourrait vous empêcher de rencontrer le problème. Le bloc le plus intérieur soulèverait toujours une exception, il ne promet donc jamais de durabilité. Mais cela perd une certaine flexibilité.
Une meilleure solution serait d'avoir plus de granularité sur ce que vous demandez. Si vous pouvez demander séparément l'atomicité et la durabilité, vous pouvez effectuer l'imbrication. Il vous suffit de vous assurer que chaque bloc demandant la durabilité est en dehors de ceux qui demandent l'atomicité. La demande de durabilité à l'intérieur d'un bloc demandant l'atomicité devrait déclencher une exception.
atomic
est censé fournir la partie atomicité. Autant que je sache Django 1.6.1 n'a pas de décorateur, ce qui peut demander de la durabilité. J'ai essayé d'en écrire un, et publié sur codereview.