【问题标题】:Django, how to make a view atomic?Django,如何使视图原子化?
【发布时间】:2009-07-20 19:38:26
【问题描述】:

我有一个简单的 django 应用程序来模拟股票市场,用户进来买/卖。当他们选择交易时,

  1. 读取市场价格,并且
  2. 根据买入/卖出订单,市场价格上涨/下跌。

我不确定这在 django 中是如何工作的,但是有没有办法使视图原子化?即我担心用户 A 的操作可能会读取价格,但在由于他的订单而更新之前,用户 B 的操作会读取价格。

在网上找不到一个简单、干净的解决方案。谢谢。

【问题讨论】:

  • 如果用户 A 花了 10 分钟阅读页面并做出决定会怎样?应该允许用户B下订单吗?
  • 数据库事务是原子的,而不是 Web 服务器页面视图。要序列化两个用户的独立请求,您无能为力。

标签: python database django locking atomic


【解决方案1】:

这是数据库事务,带有一些注释。 Postgresql 的所有注释;所有数据库都有锁定机制,但细节不同。

默认情况下,许多数据库不会执行此级别的锁定,即使您在事务中也是如此。您需要明确锁定数据。

在 Postgresql 中,您可能需要 SELECT ... FOR UPDATE,这将锁定返回的行。如果另一个用户要更新它们,您需要在每个想要阻止的 SELECT 上使用 FOR UPDATE。

不幸的是,没有办法在 Django 的 ORM 中执行 FOR UPDATE。据我所知,您要么需要稍微破解 ORM 或使用原始 SQL。如果这是低性能代码,并且您有能力序列化对表的所有访问,则可以使用表级 LOCK IN EXCLUSIVE MODE,它将序列化整个表。

http://www.postgresql.org/docs/current/static/explicit-locking.html

http://www.postgresql.org/docs/current/static/sql-lock.html

http://www.postgresql.org/docs/current/static/sql-select.html

【讨论】:

  • ORM 并不是要替代 SQL 或避免使用 SQL,所以手写这些东西是可以的。
  • 不,这不好。必须做一些直接的工作是很好的——比如,将“.select_mode('FOR UPDATE')”添加到 QuerySet 而不是使用专门的“.select_for_update()”方法。仅仅因为您需要添加一个标志,就必须手动编写整个内容,或者必须跳圈,这是完全不能接受的。 Django 的 ORM 在这种事情上还很不成熟。
  • (当然,我说的不是 ORM 词汇表之外的复杂、专门的查询。这不是那种。)
  • 如果您在读取视图中执行SELECT FOR UPDATE,并且用户离开了,该行锁定了多长时间?此外,在用户体验方面,id 可能是不可接受的,仅仅因为用户已经查看(或显示编辑意图)一个项目,将其锁定以使其他人无法编辑,这会激怒一些用户。
  • select_for_update() 添加到 Django 1.4
【解决方案2】:

很老的问题,但由于1.6 你可以使用transaction.atomic() 作为装饰器。

views.py

@transaction.atomic()
def stock_action(request):
  #trade here

【讨论】:

    【解决方案3】:

    将读取的数据库查询和更新的数据库查询包装在事务中。语法取决于您使用的 ORM。

    【讨论】:

    • 这对于 Postgresql 是不正确的。您不能假设在事务中读取行会锁定它们。
    猜你喜欢
    • 2019-10-17
    • 2020-09-27
    • 2018-08-06
    • 2012-07-03
    • 2019-03-16
    • 1970-01-01
    • 2012-03-22
    • 2016-02-23
    • 1970-01-01
    相关资源
    最近更新 更多