乐观的“锁定"状态.与Django交易 [英] Optimistic "locking" with Django transactions

查看:71
本文介绍了乐观的“锁定"状态.与Django交易的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个函数fn(),该函数需要自动执行一些数据库工作,该数据库工作依赖于在执行过程中保持不变的大多数数据集(大多数情况下为真).

I have a function fn() that needs to atomically do some database work that relies on some set of data not changing during its execution (true most of the time).

在Django中实现此目标的正确方法是什么?基本上我想做这样的事情:

What is the correct way to implement this in Django? Basically I'd like to do something like this:

def ensure_fn_runs_successfully():
  # While commit unsuccessful, keep trying
  while not fn():
    pass

@transaction.atomic
def fn():
  data = read_data_that_must_not_change()

  ... do some operations with the data and perform database operations ...

  # Assume it returns true if commit was successful, otherwise false
  return commit_only_if_the_data_actually_didnt_change()

@transaction.atomic解决了部分问题(数据库仅应在fn运行之前或成功运行fn之后才能看到状态),但是我不确定是否存在一个很好的原语来执行commit_only_if_the_data_actually_didnt_change,如果失败则重试该操作.

@transaction.atomic takes care of part of the problem (database should only ever see the state before fn runs or after fn runs successfully), but I'm not sure if there exists a good primitive to do the commit_only_if_the_data_actually_didnt_change, and retrying the operation if it fails.

要验证数据没有变化,仅检查查询返回的项数是否与函数开头的值相同就足够了;但是,我不知道是否有任何原语可以让您在没有竞争条件的情况下同时进行检查和提交决定.

To verify the data didn't change, it would be enough to just check the count of items returned for a query is the same as it was at the beginning of the function; however, I don't know if there are any primitives that let you make the check and commit decision at the same time / without race condition.

推荐答案

如果您在事务块中,唯一可以更改正在读取的数据的是同一事务块中的其他操作 强>.因此,只要fn()不对data进行任何更改,就可以保证除非fn()更改数据,否则数据不会更改.这就是交易要解决的问题.

If you are in a transaction block, the only thing that can change the data that you are reading are other operations within that same transaction block. So as long as fn() does not make any changes to data, you are guaranteed that the data will not change unless fn() changes it. That is the problem that transactions are meant to solve.

如果data可以在fn()的范围内更改,只需跟踪其更改的地方或最终结果即可.

If data can change within the confines of fn() just keep track of the places where it changes or keep track of the final result.

@transaction.atomic
def fn():
  data = read_data_that_must_not_change()
  original_data = copy.copy(data)
  ... do some operations with the data and perform database operations ...

  # Assume it returns true if commit was successful, otherwise false
  if data != original_data:
    raise Exception('Oh no!  Data changed!') 
    # raising in exception is how you prevent transaction.atomic
    # from committing
  return commit_only_if_the_data_actually_didnt_change()

然后像下面这样处理while循环中的异常:

And then handle the exception in you while loop like so:

while True:
    try:
        fn()
        break
    except:
        time.sleep(10) # ten second cool off
        pass

这篇关于乐观的“锁定"状态.与Django交易的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆