Django 为你提供几种方法来控制如何管理数据库事务。

django1.8.2中文文档翻译

Django 数据库事务


Django’s default transaction behavior

具体细节看下面.

update() 查询.

测试用例 也包装了事务性能原因的测试类


True

如果在view这里产生一个异常,Django就会回滚这次事务

但是最后你的视图,要么是所有改变都提交执行,要么是都不提交。

警告

其对性能的影响依赖于应用程序对数据库的查询语句效率和数据库当前的锁竞争情况。

预请求事务和流式响应

因为视图调用已经返回,这样代码在事务的外部运行。

一般而言,在产生一个流式响应时,不建议再进行写数据库的操作,因为没有明智的方式在开始发送响应之后来处理错误。

atomic()装饰器把这一功能简单地加载到视图函数上。 

诸如模板响应之类的中间件(Middleware)操作是运行在事务之外的。

ATOMIC_REQUESTS被启用后,仍然有办法来阻止视图运行一个事务操作。

non_atomic_requests(using=None)[source]

ATOMIC_REQUESTS设定的视图:

from django.db import transaction

@transaction.non_atomic_requests
def my_view(request):
    do_stuff()

@transaction.non_atomic_requests(using='other')
def my_other_view(request):
    do_stuff_on_the_other_database()

它将仅工作在设定了此装饰器的视图上。


Django提供了单一的API来控制数据库事务。

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

如果有异常,则更改将回滚。

在下面的例子里,使用with语句,当一个内部块完成后,如果某个异常在外部块被抛出,内部块上的操作仍然可以回滚(前提是外部块也被atomic装饰过)。

装饰器:

from django.db import transaction

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

atomic被用作 上下文管理器:

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()

atomic装饰的代码在一个 try/except 块内允许使用常见的完整性错误检测语法:

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()上的尝试操作已经被安全回滚,所以若有必要,这个异常的句柄也能够操作数据库。

atomic里捕获异常!

这可能会导致意想不到的后果。

当一个ORM-相关的信号句柄操作异常时,你可能也会遇到类似的情形。

这种模式还有另一个优势:它明确了当一个异常发生时,哪些操作将回滚。

如果你是从原始的SQL查询语句中捕获异常,则Django的行为是不明确的,而且是依赖于数据库的。

atomic代码块内试图 commit, roll back,或者更改数据库autocommit的状态都会导致异常。

 数据库。

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

  • atomic 代码块时会打开一个事务;
  • atomic代码块时会创建一个保存点;
  • 当退出内部块时会释放或回滚保存点;
  • 当退出外部块时提交或回退事物。

它的缺点是打破了上述错误处理的原则。

savepoint=False,这将会产生一个错误。

性能考虑

atomic()来执行长运行的进程,将其置于Django的请求/响应周期之外是尤其重要。



这样事务必须明确是提交还是回滚。

也就是说, 不但每个查询是每个事物的开始,而且每个事物会自动提交或回滚,这取决于该查询是否成功执行。

Django覆盖了这个默认规范并且将autocommit设置为 on.

关闭事务管理器, 但不建议这样做。


你只能遵照数据库层面的规则行为。

因此,这最好只用于你自定义的事物控制中间件或者是一些比较奇特的场景。

提交后执行操作

Django1.9的新特性

有时候你想在事务成功提交后执行一些与当前数据库事务相关的操作。比如说Celery任务,邮件通知,或者缓存失效。

Django提供了on_commit()方法来注册一些只有在事务成功提交后才执行的回调函数。

on_commit(func, using=None)[source]

on_commit()传入任何没有参数的函数。

from django.db import transaction

def do_something():
    pass  # send a mail, invalidate a cache, fire off a Celery task, etc.

transaction.on_commit(do_something)

你也可以传入匿名函数。

transaction.on_commit(lambda: some_celery_task.delay('arg1'))

???当假定的数据库写操作被成功提交后,你传入的这个函数将会被立即执行。

The function you pass in will be called immediately after a hypothetical database write made where on_commit() is called would be successfully committed.

当你在不存在开启的事务的时候使用了on_commit(),回调函数将会立即被执行。

如果假定的数据库写操作变成了回滚(典型的是一个未处理的异常在atomic()中发生),你传入的函数将会被废弃掉,将永远不会被执行。


警告

它遵守数据库的相关特性并且防止了非法操作。

低级别 API仅仅用于你自定义的事务管理场景。


django.db.transaction模块里,Django提供了一个简单的API, 用于管理每个数据库的自提交状态。

get_autocommit(using=None)[source]
set_autocommit(autocommit, using=None)[source]

 数据库。

如果你把它关掉了,那么你有义务恢复它。

请仔细检查你当前正在使用的数据库适配器文档。

rollback()这样的语法操作。

atomic()代码块处于活跃状态时,Django会拒绝将autocommit从on的状态调整为off,因为这样会破坏原子性。 


即使程序在运行时崩溃了,数据库可以确保事物集中的所有变更要么都被提交,要么都被放弃。

set_autocommit()设置为disable状态。

django.db.transaction定义的。

commit(using=None)[source]
rollback(using=None)[source]

 数据库.

atomic()程序块在运行状态,Django会拒绝 commit 或rollback操作,因为这些操作是自动的。


在其他的数据库后端虽然也提供保存点的函数,但其实它们是空操作,实际不起任何作用。

transaction.rollback()对整个事物进行回滚.

atomic()而不是下面描述的函数功能,当然他们也是公开API的一部分,并且现在也没有废除它们的计划。

 数据库。

django.db.transaction里的三个函数来控制的:

savepoint(using=None)[source]

sid).

savepoint_commit(sid, using=None)[source]

自创建保存点进行的更改将成为事物的一部分。

savepoint_rollback(sid, using=None)[source]

sid.

如果不支持保存点或者数据库未处于autocommit模式,这些函数将什么也不做。

此外,还有一个实用的功能:

clean_savepoints(using=None)[source]

重置用来生成唯一保存点ID的计数器:

下面的例子演示了如何使用保存点:

from django.db import transaction

# open a transaction
@transaction.atomic
def viewfunc(request):

    a.save()
    # transaction now contains a.save()

    sid = transaction.savepoint()

    b.save()
    # transaction now contains a.save() and b.save()

    if want_to_keep_b:
        transaction.savepoint_commit(sid)
        # open transaction still contains a.save() and b.save()
    else:
        transaction.savepoint_rollback(sid)
        # open transaction now contains only a.save()

为了避免这样,你可以在下面函数中控制回滚行为。

get_rollback(using=None)[source]
set_rollback(rollback, using=None)[source]

这对在没有抛出异常的情况下触发一个回滚操作是很有用的。

否则,你打破原子性,并且数据损坏可能会发生。



sqlite3模块的设计缺陷导致其很难使用。

这个问题有两个后果:

  • atomic() 块之内。
  • atomic() 的。


MySQL事物的相关信息.

如果你安装的MySQL确定支持事物, Django会遵循本文所介绍的关于事务的处理原则。


注意

atomic() 自动控制的情况下。

save()是不太可能导致PostgreSQL异常的, 但仍然有更高级模式用法的可能, 例如在一个有唯一约束的字段保存对象, 保存使用force_insert/force_update 标志,或者调用一些定制化的SQL。

有几种方法可以从这种错误中恢复过来。


例如:

a.save() # Succeeds, but may be undone by transaction rollback
try:
    b.save() # Could throw exception
except IntegrityError:
    transaction.rollback()
c.save() # Succeeds, but a.save() may have been undone

a.save()所保存的变更将会丢失,即使这个操作自身没有产生错误。


例如:

a.save() # Succeeds, and never undone by savepoint rollback
sid = transaction.savepoint()
try:
    b.save() # Could throw exception
    transaction.savepoint_commit(sid)
except IntegrityError:
    transaction.savepoint_rollback(sid)
c.save() # Succeeds, and a.save() is never undone

a.save() 所做的更改将不会丢失。

相关文章: