繁体   English   中英

Django 记录锁定和原子事务

[英]Django Record Locking and Atomic Transactions

我正在尝试在我正在做的项目中实施一些关键更新。 总之,我需要从一个工作文件中获取信息,该文件进行一些进一步的处理,然后将其更新为最终文件。 此信息来自不同的来源,因此最好在中间文件上执行,然后将其写入最终文件。

我的问题是一些细节线数据在途中丢失了。 我在下面的文件中复制了这个问题以消除任何杂物。 只需在 manage.py shell 中运行函数即可。 这显示在 Mariadb 和 Postgresql 中。

有没有更好的方法来实现这一点而不是解决方法?

模型.py:

import random
from decimal import Decimal

from django.db import models, transaction


class Head(models.Model):
    name = models.CharField(max_length=20, default="")
    h1_text = models.CharField(max_length=20, default="")

    def update(self):
        tmp1 = Tmp1Head()
        tmp1.name = self.h1_text
        tmp1.save()
        for line in self.head_lines.all():
            tl1 = Tmp1Line()
            tl1.head = tmp1
            tl1.data_text = line.data_text
            tl1.t1_data = line.t1_data
            tl1.t2_data = Decimal(random.random())
            tl1.save()

        with transaction.atomic():
            transaction.on_commit(tmp1.update)

        tmp1.delete()  # All fine - remove this work transaction.
        return True


class Line(models.Model):
    head = models.ForeignKey(Head, on_delete=models.CASCADE, related_name='head_lines')
    data_text = models.CharField(max_length=20, default="")
    t1_data = models.DecimalField(max_digits=12, decimal_places=2)


class Tmp1Head(models.Model):
    name = models.CharField(max_length=20, default="")

    def update(self):
        tmp2 = Tmp2Head()
        tmp2.name = self.name
        tmp2.save()
        for line in self.tmp1_lines.all():
            tl2 = Tmp2Line()
            tl2.head = tmp2
            tl2.data_summary = line.data_text
            tl2.final_data = line.t1_data * line.t2_data
            tl2.save()


class Tmp1Line(models.Model):
    head = models.ForeignKey(Tmp1Head, on_delete=models.CASCADE, related_name='tmp1_lines')
    data_text = models.CharField(max_length=20, default="")
    t1_data = models.DecimalField(max_digits=12, decimal_places=2)
    t2_data = models.DecimalField(max_digits=12, decimal_places=2)


class Tmp2Head(models.Model):
    name = models.CharField(max_length=20, default="")


class Tmp2Line(models.Model):
    head = models.ForeignKey(Tmp2Head, on_delete=models.CASCADE, related_name='tmp2_lines')
    data_summary = models.CharField(max_length=20, default="")
    final_data = models.DecimalField(max_digits=12, decimal_places=2)

视图.py

from .models import *


def populate():
    Head.objects.all().delete()
    Tmp1Head.objects.all().delete()
    Tmp2Head.objects.all().delete()

    head = Head.objects.create(name="test", h1_text="test text")
    for tmp in range(1, 5):
        Line.objects.create(head=head,
                            data_text=f"data line:{tmp}",
                            t1_data=tmp)


def test1(): # all fine but no locking.
    batch = Head.objects.first()
    batch.update()


def test2():  # record locking but the data lines get lost in the final table.
    with transaction.atomic():
        batch = Head.objects.select_for_update().first()
        batch.update()


def test3():  # record locking, no data lost, but the temp data is not removed.
    """
    Same as test 2 but remove the below line from update function in the Head model.
        tmp1.delete()  # All fine - remove this work transaction.
    """
    with transaction.atomic():
        batch = Head.objects.select_for_update().first()
        batch.update()

为了解决这个问题,我拿走了保存点,现在一切似乎都很好。 它应该是安全的,因为只有程序才能访问临时文件。

我从models.py中删除了这个:

# with transaction.atomic():
# transaction.on_commit(tmp1.update)
tmp1.update()

暂无
暂无

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

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