Django4.0 数据库事务-底层API
自动提交
Django 在 django.db.transaction
模块中提供了一个 API 来管理每个数据库连接的自动提交状态。
get_autocommit(using=None)
set_autocommit(autocommit, using=None)
这些函数使接受一个 using
参数表示所要操作的数据库。如果未提供,则 Django 使用 "default
" 数据库。
自动提交默认为开启,如果你将它关闭,自己承担后果。
一旦你关闭了自动提交, Django 将无法帮助你,数据库将会按照你使用的数据库适配器的默认行为进行操作。
在关闭自动提交之前,你必须确保当前没有活动的事务,通常你可以执行 commit()
或者 rollback()
函数以达到该条件。
当一个原子 atomic()
事务处于活动状态时, Django 将会拒绝关闭自动提交的请求,因为这样会破坏原子性。
事务
事务是指具有原子性的一系列数据库操作。即使你的程序崩溃,数据库也会确保这些操作要么全部完成要么全部都未执行。
Django 不提供启动事务的 API。 启动事务的预期方法是使用 set_autocommit()
禁用自动提交。
进入事务后,你可以选择在 commit()
之前应用执行的更改,或者使用 rollback()
取消它们。这些函数在 django.db.transaction
中定义。
commit(using=None)
rollback(using=None)
这些函数使接受一个 using
参数表示所要操作的数据库。如果未提供,则 Django 使用 "default
" 数据库。
当一个原子 atomic()
事务处于活动状态时, Django 将会拒绝进行事务提交或者事务回滚,因为这样会破坏原子性。
保存点
保存点在事务中是标记物,它可以使得回滚部分事务,而不是所有事务。 SQLite, PostgreSQL, Oracle, 和 MySQL (当使用 InnoDB 存储引擎) 后端提供了保存点。其他后端提供了保存点函数,但它们是空操作——它们实际上没有做任何事情。
如果你正在使用 Django 的默认行为——自动提交,保存点并不特别有用。尽管,一旦你用 atomic()
打开了一个事务,那么需要构建一系列的等待提交或回滚的数据库操作。如果发出回滚,那么会回滚整个事务。保存点有能力执行颗粒度级别的回滚,而不是由 transaction.rollback()
执行的完全回滚。
当嵌套了 atomic()
装饰器,它会创建一个保存点来允许部分提交或回滚。强烈推荐只使用 atomic()
而不是下面描述的函数,但它们仍然是公共 API 的一部分,而且没计划要弃用它们。
这里的每一个函数使用 using
参数,这个参数为应用的数据库名。如果没有 using
参数,那么会使用 "default
" 数据库。
保存点由 django.db.transaction
中的三个函数来控制:
savepoint(using=None)
创建新的保存点。这标志着事务中已知处于“良好”状态的一个点。返回保存点ID (sid
) 。
savepoint_commit(sid, using=None)
释放保存点 sid
。自保存点被创建依赖执行的更改成为事务的一部分。
savepoint_rollback(sid, using=None)
回滚事务来保存 sid
。
如果不支持保存点或数据库在自动模式时,这些函数不执行操作。
另外,还有一个实用功能:
clean_savepoints(using=None)
重置用于生成唯一保存点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()
保存点可能通过执行部分回滚来恢复数据库错误。如果你在 atomic()
块中执行此操作,那么整个块将仍然被回滚,因为它不知道你已经处理了较低级别的情况。为了防止发生,你可以使用下面的函数控制回滚行为。
get_rollback(using=None)
set_rollback(rollback, using=None)
当存在内部原子块时,设置回滚标记为 True
将强制回滚。这对于触发回滚而不引发异常可能很有用。
将它设置为 False
会防止这样的回滚。在这样做之前,确保你已经将事务回滚到当前原子块中一个正常的保存点。否则你会破坏原子性并且可能发生数据损坏。