Django4 中文入门教程 Django4.0 数据库事务-特定于数据的注释

2024-02-25 开发教程 Django4 中文入门教程 匿名 6

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()​ 引发异常的情况下被撤销。