简体   繁体   English

Django transaction.atomic()保证原子READ + WRITE?

[英]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? transaction.atomic()保证吗?

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? 如果他们没有任何问题,那么实现原子READS和WRITES的正确方法是什么?


My example that I have tested. 我测试过的例子。

Put the Test class somewhere in your model. Test类放在模型中的某个位置。 atomic_test.py and atomic_test2.py should be saved as management commands. atomic_test.pyatomic_test2.py应保存为管理命令。 Run python manage.py atomic_test first, then python manage.py atomic_test2 . 首先运行python manage.py atomic_test ,然后运行python manage.py atomic_test2 The second script does not block and its changes are lost. 第二个脚本不会阻止,其更改将丢失。

models.py models.py

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

atomic_test.py 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 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

Django's transaction.atomic() is a thin abstraction over the transaction facilities of the database. Django的transaction.atomic()是对数据库事务工具的精简抽象。 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 ). (例如,在PostgreSQL中,相关文档是事务隔离显式锁定 )。

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). 至于您的特定测试用例,可以通过在Django查询集上使用select_for_update()方法来实现您想要的行为(如果您的数据库支持它)。 Something like: 就像是:

in atomic_test.py 在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 在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. 第二个应该阻塞,直到第一个完成,并看到新值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. 其他选项包括使用SERIALIZABLE事务隔离级别或使用行锁,但Django不提供方便的API来执行这些操作。

It would be much better to update atomically on the database using the F function: 使用F函数在数据库上进行原子更新会好得多:

from django.db.models import F
Test.objects.filter(id=1).update(value=F("value") + 10)

(This generates SQL something like "UPDATE test_test SET value = value + 10 WHERE id = 1" ) (这会生成类似"UPDATE test_test SET value = value + 10 WHERE id = 1"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM