Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django transaction.atomic() guarantees atomic READ + WRITE?

I need to make sure that an object that is read from the database and written back, cannot be modified in the meantime by another request/process.

Does transaction.atomic() guarantee that?

My tests so far tell me no. If there's nothing wrong with them what would be the right way to achieve atomic READS and WRITES?


My example that I have tested.

Put the Test class somewhere in your model. atomic_test.py and atomic_test2.py should be saved as management commands. Run python manage.py atomic_test first, then python manage.py atomic_test2. The second script does not block and its changes are lost.

models.py

class Test(models.Model):
    value = models.IntegerField()

atomic_test.py

from django.core.management.base import NoArgsCommand
from django.db import transaction
from time import sleep
from core.models import Test

class Command(NoArgsCommand):
    option_list = NoArgsCommand.option_list

    def handle(self, **options):
        Test.objects.all().delete()
        t = Test(value=50)
        t.save()

        print '1 started'
        with transaction.atomic():
            t = Test.objects.all()[0]
            sleep(10)
            t.value = t.value + 10
            t.save()
        print '1 finished: %s' %Test.objects.all()[0].value

atomic_test2.py

from django.core.management.base import NoArgsCommand
from django.db import transaction
from time import sleep
from core.models import Test

class Command(NoArgsCommand):
    option_list = NoArgsCommand.option_list

    def handle(self, **options):
        print '2 started'
        with transaction.atomic():
            t = Test.objects.all()[0]
            t.value = t.value - 20
            t.save()
        print '2 finished: %s' %Test.objects.all()[0].value
like image 738
kev Avatar asked Nov 27 '14 04:11

kev


People also ask

What does transaction atomic do in Django?

Django provides a single API to control database transactions. 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.

What is atomic transaction in SOA?

An atomic transaction is a single, irreducible component of a classic transaction, such as making a purchase. WS-AT ensures that if a single atomic transaction fails, the whole transaction fails: A partial transaction cannot take place.

Is SQL transaction atomic?

In SQL databases transaction atomicity is implemented most frequently using write-ahead logging (meaning that the transaction log entries are written before the actual tables and indexes are updated).

Is Django admin atomic?

No, Django doesn't use Atomic Transaction by default.


1 Answers

Django's transaction.atomic() is a thin abstraction over the transaction facilities of the database. So its behavior really depends on the database layer, and is specific to the type of database and its settings. So to really understand how this works you need to read and understand the transaction documentation for your database. (In PostgreSQL, for example, the relevant documentation is Transaction Isolation and Explicit Locking).

As for your specific test case, the behavior you want can be achieved by using the select_for_update() method on a Django queryset (if your database supports it). Something like:

in atomic_test.py

with transaction.atomic():
    t = Test.objects.filter(id=1).select_for_update()[0]
    sleep(10) 
    t.value = t.value + 10
    t.save()

in atomic_test2.py

with transaction.atomic():
    t = Test.objects.filter(id=1).select_for_update()[0]
    t.value = t.value - 20
    t.save()

The second one should block until the first one finishes, and see the new value of 60.

Other options include using the SERIALIZABLE transaction isolation level or using a row lock, though Django doesn't provide a convenient API for doing those things.

like image 81
Kevin Christopher Henry Avatar answered Sep 18 '22 07:09

Kevin Christopher Henry