Django4.0 数据库事务-特定于数据的注释
SQLite 中的保存点
虽然 SQLite 支持保存点时,但 sqlite3 模块中的一个设计缺陷使得它们几乎无法使用。
当启用自动提交时,保存点没有意义。当关闭时,sqlite3 会在保存点语句之前隐式提交。(事实上,它会在除了 SELECT
, INSERT
, UPDATE
, DELETE
和REPLACE
之前的任何语句之前提交)这个 Bug 有两个后果:
- 保存点的底层API只能在事务中可用,即在
atomic()
块中。 - 当关闭自动提交时,不能使用
atomic()
。
MySQL 中的事务
如果你正在使用 MySQL,表可能支持或不支持事务;它取决于 MySQL 版本和表的类型。(表类型是指 "InnoDB" 或 "MyISAM" 之类的东西)MySQL 事务的特性超出了本文的范围,但 MySQL 站点有 MySQL 事务的相关信息。
如果 MySQL 安装时没有支持事务,然后 Django 将始终在自动提交模式中运行:语句将在它们调用的时候被执行和提交。如果 MySQL 安装时支持了事务,Django 将像本文说的那样处理事务。
处理 PostgreSQL 事务中的异常
注解:只有在实现自有的事务管理时,这部分才有用。这个问题不会发生在 Django 默认模式里,并且 atomic()
会自动处理它。
在一个事务里,当对 PostgreSQL 游标的调用引发了异常(通常是 IntegrityError
),在同一事务中的随后的SQL 将会出现 "current transaction is aborted, queries ignored until end of transaction block
" 的错误 。虽然 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
调用 transaction.rollback()
回滚整个事务。任何未提交的数据库操作会被丢弃。在这个例子里, a.save()
做的改变会丢失,即使操作本身没有引发错误。
保存点回滚
你可以使用 savepoints
来控制回滚的程度。执行可能失败的数据库操作之前,你可以设置或更新保存点;这样,如果操作失败,你可以回滚单一的错误操作,而不是回滚整个事务。比如:
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()
将不会在 b.save()
引发异常的情况下被撤销。
更多建议: