簡體   English   中英

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

[英]Django transaction.atomic() guarantees atomic READ + WRITE?

我需要確保從數據庫讀取並寫回的對象不能在此期間被另一個請求/進程修改。

transaction.atomic()保證嗎?

到目前為止我的測試告訴我沒有。 如果他們沒有任何問題,那么實現原子READS和WRITES的正確方法是什么?


我測試過的例子。

Test類放在模型中的某個位置。 atomic_test.pyatomic_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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM