Django 1.6 proposes @transaction.atomic
as part of the rehaul in the transaction management from 1.5.
I have a function which is called by a Django management command which is in turn called by cron, i.e. no HTTP request triggering transactions in this case. Snippet:
from django.db import transaction @transaction.commit_on_success def my_function(): # code here
In the above code block commit_on_success
uses a single transaction for all the work done in my_function
.
Does replacing @transaction.commit_on_success
with @transaction.atomic
result in the identical behaviour? @transaction.atomic
docs state:
Atomicity is the defining property of database transactions. atomic allows us to create a block of code within which the atomicity on the database is guaranteed. If the block of code is successfully completed, the changes are committed to the database. If there is an exception, the changes are rolled back.
I take it that they result in the same behaviour; correct?
Based on the documentation I have read on the subject, there is a significant difference when these decorators are nested.
Nesting two atomic
blocks does not work the same as nesting two commit_on_success
blocks.
The problem is that there are two guarantees that you would like to have from these blocks.
It is impossible to provide both guarantees when blocks are nested. If an exception is raised after leaving the innermost block but before leaving the outermost block, you will have to fail in one of two ways:
Here is where you find the difference. Using commit_on_success
would give durability for the innermost block, but no atomicity for the outermost block. Using atomic
would give atomicity for the outermost block, but no durability for the innermost block.
Simply raising an exception in case of nesting could prevent you from running into the problem. The innermost block would always raise an exception, thus it never promises any durability. But this loses some flexibility.
A better solution would be to have more granularity about what you are asking for. If you can separately ask for atomicity and durability, then you can perform nesting. You just have to ensure that every block requesting durability is outside those requesting atomicity. Requesting durability inside a block requesting atomicity would have to raise an exception.
atomic
is supposed to provide the atomicity part. As far as I can tell django 1.6.1 does not have a decorator, which can ask for durability. I tried to write one, and posted it on codereview.
Yes. You should use atomic
in the places where you previously used commit_on_success
.
Since the new transaction system is designed to be more robust and consistent, though, it's possible that you could see different behavior. For example, if you catch database errors and try to continue on you will see a TransactionManagementError
, whereas the previous behavior was undefined and probably case-dependent.
But, if you're doing things properly, everything should continue to work the same way.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With