【问题标题】:How to avoid/fix django's DatabaseTransactionError如何避免/修复 django 数据库事务错误
【发布时间】:2015-11-18 01:11:31
【问题描述】:

我有以下受竞争条件约束的(转述)代码:

def calculate_and_cache(template, template_response):
    # run a fairly slow and intensive calculation:
    calculated_object = calculate_slowly(template, template_response)
    cached_calculation = Calculation(calculated=calculated_object,
                                     template=template,
                                     template_response=template_response)
    # try to save the calculation just computed:
    try:
        cached_calculation.save()
        return cached_calculation
    # if another thread beat you to saving this, catch the exception
    # but return the object that was just calculated
    except DatabaseError as error:
        log(error)
        return cached_calculation

它引发了 DatabaseTransactionError:

TransactionManagementError: An error occurred in the current transaction.
You can't execute queries until the end of the 'atomic' block.

The docs 对 DTE 有这样的看法:

退出原子块时,Django 会查看它是正常退出还是异常退出,以确定是提交还是回滚....如果您尝试在回滚发生之前运行数据库查询,Django 将引发一个 TransactionManagementError。

但是they 也有这个,关于他们还有更模糊的说法:

TransactionManagementError 是针对与数据库事务相关的所有问题引发的。

我的问题,按一般性升序排列:

  1. 捕获DatabaseError 是否会通过让save() 在返回对象的同时优雅退出来真正解决竞争条件?
  2. 上述代码中的原子块从哪里开始,又在哪里结束?
  3. 我做错了什么,我该如何解决?

【问题讨论】:

    标签: python django django-orm


    【解决方案1】:

    controlling transactions explicitly 上的 Django 文档有一个在原子块中捕获异常的示例。

    在您的情况下,您似乎根本没有使用 atomic 装饰器,因此首先您需要添加所需的导入。

    from django.db import transaction
    

    然后您需要将可能引发数据库错误的代码移动到原子块中:

    try:
        with transaction.atomic():
            cached_calculation.save()
        return cached_calculation
    # if another thread beat you to saving this, catch the exception
    # but return the object that was just calculated
    except DatabaseError as error:
        log(error)
        return cached_calculation
    

    【讨论】:

    • 鉴于我没有使用 atomic 装饰器,我在退出原子块时遇到问题是怎么回事?
    • 据我了解,您不会遇到“退出原子块”的问题。问题是您试图在未回滚的错误之后执行查询。
    • 嗯。我做的唯一查询似乎是cached_calculation.save(),我也怀疑这是引发错误的部分——该查询如何既导致错误又跟随错误?
    • 此外,原子块的作用是使查询集合完全或全部发生。这如何适用于单个查询?
    • 其实只是读到这个:stackoverflow.com/questions/21468742/…,显然单个查询可以是非原子的
    猜你喜欢
    • 1970-01-01
    • 2018-05-25
    • 2019-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-10
    相关资源
    最近更新 更多