保存mod时确保原子性

2024-10-02 08:20:54 发布

您现在位置:Python中文网/ 问答频道 /正文

我是Django的新手,不知道如何管理并发性。你知道吗

我正在建立一个应用程序来储备设备。 我有一个预订模型,有很多设备。 当我创建新的预订时,我必须确保所有的设备都可用。 我的代码的第一个版本不关心并发性:

def validate_reservation(keys, begin, end):

   eqpts = Equipment.objects.filter(pk__in=keys)
   if all(eqpt.is_available(begin, end) for eqpt in eqpts):
      res = Reservation(eqpts, begin, end)
      res.save()
      return True
   else:
      return False

isu available方法检查给定日期是否已有任何预订:

  def is_available(self, begin, end):
        return not self.reservations.filter(begin__lte=end, end__gte=begin).exists()

问题是,如果第一个用户在第二个用户检查了设备的可用性之后保存了他的预订,那么运行此代码的两个用户可能会创建冲突的预订。你知道吗

我相信我可以通过交易解决问题,所以我想到了:

def validate_reservation(keys, begin, end):

    with transaction.atomic():
       eqpts = Equipment.objects.select_for_update().filter(pk__in=keys)
       if all(eqpt.is_available(begin, end) for eqpt in eqpts):
          res = Reservation(eqpts, begin, end)
          res.save()
          return True
       else:
          return False

这是否具有预期的行为? 如何知道事务是否失败并通知用户?你知道吗

有没有其他更好的方法?你知道吗


Tags: 代码用户inforreturnisdefres
1条回答
网友
1楼 · 发布于 2024-10-02 08:20:54

是的,只要您在修改任何可能影响可用性检查的内容之前始终使用select_for_update(),这应该是有效的。你知道吗

此代码不会干扰自身,因为select_for_update()将在开始时获取键行上的行级锁。但是假设您有另一个视图,允许用户输入预约pk,更改开始和结束时间,或者添加新设备。这可能会导致不一致,除非对与该Reservation关联的Equipment行显式执行相同的select_for_update()。你知道吗

注意你的支票不是很有效。无论何时在循环中执行查询,都应该寻找替代方法。在这种情况下,您应该能够找到与单个查询(即JOINs表)的冲突:

has_conflict = Reservation.objects.filter(begin__lte=end,
                                          end__gte=begin,
                                          equipment__pk__in=keys).exists()

(当然,您仍然存在并发问题,因此仍然需要获取适当的锁或使用不同的事务隔离级别。)

如何知道事务是否失败并通知用户?

事务不会失败,它只会阻塞直到锁被释放。如果希望事务失败,可以使用select_for_update(nowait=True)(在某些数据库上)。你知道吗

相关问题 更多 >

    热门问题