[英]Django transaction.atomic() guarantees atomic READ + WRITE?
我需要确保从数据库读取并写回的对象不能在此期间被另一个请求/进程修改。
transaction.atomic()保证吗?
到目前为止我的测试告诉我没有。 如果他们没有任何问题,那么实现原子READS和WRITES的正确方法是什么?
我测试过的例子。
将Test类放在模型中的某个位置。 atomic_test.py和atomic_test2.py应保存为管理命令。 首先运行python manage.py atomic_test ,然后运行python manage.py atomic_test2 。 第二个脚本不会阻止,其更改将丢失。
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
Django的transaction.atomic()
是对数据库事务工具的精简抽象。 所以它的行为实际上取决于数据库层,并且特定于数据库的类型及其设置。 因此,要真正了解其工作原理,您需要阅读并理解数据库的事务文档。 (例如,在PostgreSQL中,相关文档是事务隔离和显式锁定 )。
至于您的特定测试用例,可以通过在Django查询集上使用select_for_update()
方法来实现您想要的行为(如果您的数据库支持它)。 就像是:
在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()
在atomic_test2.py中
with transaction.atomic():
t = Test.objects.filter(id=1).select_for_update()[0]
t.value = t.value - 20
t.save()
第二个应该阻塞,直到第一个完成,并看到新值60。
其他选项包括使用SERIALIZABLE
事务隔离级别或使用行锁,但Django不提供方便的API来执行这些操作。
使用F函数在数据库上进行原子更新会好得多:
from django.db.models import F
Test.objects.filter(id=1).update(value=F("value") + 10)
(这会生成类似"UPDATE test_test SET value = value + 10 WHERE id = 1"
)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.