当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


Python Django atomic用法及代码示例


本文介绍 django.db.transaction.atomic 的用法。

声明

atomic(using=None, savepoint=True, durable=False)[source]

原子性是数据库事务的定义属性。 atomic 允许我们创建一个代码块,在其中保证数据库的原子性。如果代码块成功完成,则将更改提交到数据库。如果出现异常,则回滚更改。

atomic 块可以嵌套。在这种情况下,当一个内部块成功完成时,如果稍后在外部块中引发异常,它的效果仍然可以回滚。

确保atomic 块始终是最外层的atomic 块有时很有用,以确保在退出块时提交任何数据库更改而没有错误。这称为持久性,可以通过设置 durable=True 来实现。如果 atomic 块嵌套在另一个块中,则会引发 RuntimeError

atomic 既可用作装饰器:

from django.db import transaction

@transaction.atomic
def viewfunc(request):
    # This code executes inside a transaction.
    do_stuff()

并作为上下文管理器:

from django.db import transaction

def viewfunc(request):
    # This code executes in autocommit mode (Django's default).
    do_stuff()

    with transaction.atomic():
        # This code executes inside a transaction.
        do_more_stuff()

在 try/except 块中包装 atomic 允许自然处理完整性错误:

from django.db import IntegrityError, transaction

@transaction.atomic
def viewfunc(request):
    create_parent()

    try:
        with transaction.atomic():
            generate_relationships()
    except IntegrityError:
        handle_exception()

    add_children()

在此示例中,即使 generate_relationships() 通过破坏完整性约束导致数据库错误,您也可以在 add_children() 中执行查询,并且来自 create_parent() 的更改仍然存在并绑定到同一个事务。请注意,在调用 handle_exception() 时,在 generate_relationships() 中尝试的任何操作都已经安全回滚,因此异常处理程序也可以在必要时对数据库进行操作。

避免在 atomic 中捕获异常!

当退出 atomic 块时,Django 会查看它是正常退出还是异常退出,以确定是提交还是回滚。如果您在 atomic 块中捕获并处理异常,您可能会向 Django 隐藏已发生问题的事实。这可能会导致意外行为。

这主要是 DatabaseError 及其子类(例如 IntegrityError )的问题。在这样的错误之后,事务被破坏,Django 将在atomic 块的末尾执行回滚。如果您尝试在回滚发生之前运行数据库查询,Django 将引发 TransactionManagementError 。当ORM-related 信号处理程序引发异常时,您也可能会遇到此行为。

捕获数据库错误的正确方法是围绕 atomic 块,如上所示。如有必要,为此添加一个额外的atomic 块。这种模式还有另一个优点:它明确界定了如果发生异常,哪些操作将被回滚。

如果您捕获原始 SQL 查询引发的异常,则 Django 的行为是未指定的并且database-dependent。

回滚事务时,您可能需要手动恢复模型状态。

当事务回滚发生时,模型字段的值不会被恢复。除非您手动恢复原始字段值,否则这可能会导致模型状态不一致。

例如,给定带有 active 字段的 MyModel,如果在事务中将 active 更新为 True 失败,则此代码段可确保最后的 if obj.active 检查使用正确的值:

from django.db import DatabaseError, transaction

obj = MyModel(active=False)
obj.active = True
try:
    with transaction.atomic():
        obj.save()
except DatabaseError:
    obj.active = False

if obj.active:
    ...

为了保证原子性,atomic 禁用了一些 API。尝试在 atomic 块内提交、回滚或更改数据库连接的自动提交状态将引发异常。

atomic 采用 using 参数,该参数应该是数据库的名称。如果没有提供这个参数,Django 使用 "default" 数据库。

在底层,Django 的事务管理代码:

  • 进入最外层atomic块时打开一个事务;
  • 进入内部atomic 块时创建保存点;
  • 退出内部块时释放或回滚到保存点;
  • 退出最外层块时提交或回滚事务。

您可以通过将 savepoint 参数设置为 False 来禁用为内部块创建保存点。如果发生异常,Django 将在退出第一个带有保存点的父块时执行回滚,如果有,则退出最外层的块。原子性仍然由外部事务保证。仅当保存点的开销很明显时才应使用此选项。它的缺点是破坏了上述错误处理。

当自动提交关闭时,您可以使用atomic。它只会使用保存点,即使是最外面的块。

相关用法


注:本文由纯净天空筛选整理自djangoproject.com大神的英文原创作品 django.db.transaction.atomic。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。