对于 AI 代理:可在 https://www.mongodb.com/zh-cn/docs/llms.txt 获取文档索引—通过在任何 URL 路径后添加 .md 可获取所有页面的 Markdown 版本。
Docs 菜单

事务和会话

在本指南中,您可以学习;了解如何使用 Django MongoDB 后端来执行事务。事务允许您运行一系列仅在提交整个ACID 事务后才更改数据的操作。如果ACID 事务中的任何操作不成功,Django MongoDB后端会停止ACID 事务,并在数据更改变得可见之前丢弃所有更改。此功能称为原子性。

在MongoDB中,事务在逻辑会话中运行。会话是要按顺序运行的一组相关读取或写入操作。会话启用为一群组操作启用因果一致性,并允许您在符合ACID的ACID 事务中运行操作,该ACID 事务满足原子性、一致性、隔离性和持久性的预期。

不支持 Django 的原生ACID 事务API ,但 Django MongoDB后端提供了可实现相同功能的自定义ACID 事务API 。要在ACID 事务中运行操作,请在原子代码区块中定义这些操作。Django MongoDB后端在内部管理会话逻辑,因此您无需在运行ACID 事务之前手动启动会话。

重要

事务限制

Django MongoDB后端的ACID 事务API有一些限制。要查看限制列表,请参阅 Django 和MongoDB功能兼容性指南中的数据库和集合支持。

The examples in this guide use the Movie model, which represents the sample_mflix.movies collection from the Atlas sample datasets. The Movie model class has the following definition:

from django.db import models
from django_mongodb_backend.fields import ArrayField
class Movie(models.Model):
title = models.CharField(max_length=200)
plot = models.TextField(blank=True)
runtime = models.IntegerField(default=0)
released = models.DateTimeField("release date", null=True, blank=True)
genres = ArrayField(models.CharField(max_length=100), null=True, blank=True)
class Meta:
db_table = "movies"
managed = False
def __str__(self):
return self.title

Movie 模型包括一个内部 Meta 类(用于指定模型元数据)和一个 __str__() 方法(用于定义模型的字符串表示形式)。 要学习;了解这些模型功能,请参阅创建模型指南中的定义模型。

您可以使用Python交互式Shell来运行代码示例。 要进入Shell ,请从项目的根目录运行以下命令:

python manage.py shell

进入Python Shell后,请确保导入以下模型和模块:

from <your application name>.models import Movie
from django.utils import timezone
from datetime import datetime

要学习;了解如何创建使用Movie 模型和Python交互式Shell与MongoDB文档交互的 Django应用程序,请访问 Django MongoDB后端入门教程。

要启动数据库ACID 事务,请调用 django_mongodb_backend.transaction.atomic() 函数。您可以将此函数用作装饰器或上下文管理器。

确保使用以下导入声明导入 transaction 模块:

from django_mongodb_backend import transaction

您可以通过在函数上方添加 @transaction.atomic 装饰器来启动数据库ACID 事务。此装饰器ACID 一致性保证函数内任何数据库操作的原子性。如果函数成功完成,则将更改提交到MongoDB。

以下示例在ACID 事务中调用 create() 方法,如果ACID 事务成功,该方法会将文档插入 sample_mflix.movies集合:

@transaction.atomic
def insert_movie_transaction():
Movie.objects.create(
title="Poor Things",
runtime=141,
genres=["Comedy", "Romance"]
)

或者,您可以使用 transaction.atomic() 上下文管理器创建原子代码区块。此示例运行与前面的示例相同的操作,但使用上下文管理器来启动ACID 事务:

def insert_movie_transaction():
with transaction.atomic():
Movie.objects.create(
title="Poor Things",
runtime=141,
genres=["Comedy", "Romance"]
)

要仅在ACID 事务成功完成时才执行某些操作,可以使用 transaction.on_commit() 函数。此函数允许您注册在ACID 事务提交到数据库后运行的回调。将函数或任何可调用对象作为参数传递给 on_commit()。

以下示例仅在相关数据库ACID 事务完成后查询 genre 值为 ["Horror", "Comedy"] 的电影:

def get_horror_comedies():
movies = Movie.objects.filter(genres=["Horror", "Comedy"])
for m in movies:
print(f"Title: {m.title}, runtime: {m.runtime}")
def insert_movie_with_callback():
with transaction.atomic():
Movie.objects.create(
title="The Substance",
runtime=140,
genres=["Horror", "Comedy"]
)
transaction.on_commit(get_horror_comedies)

要处理ACID 事务期间发生的异常,请在原子代码区块周围添加错误处理逻辑。如果在原子区块内处理错误,则可能会在 Django 中掩盖这些错误。由于 Django 使用错误来确定是提交还是回滚ACID 事务,因此这可能会导致意外行为。

如果ACID 事务不成功,Django 不会恢复对模型字段所做的任何更改。为了避免模型和数据库文档之间出现不一致,您可能需要手动恢复原始字段值。

以下示例包含错误处理逻辑,该逻辑在数据库ACID 事务失败时恢复检索到的文档的修改后的 title 值:

movie = Movie.objects.get(title="Jurassic Park")
movie.title = "Jurassic Park I"
try:
with transaction.atomic():
movie.save()
except DatabaseError:
movie.title = "Jurassic Park"
if movie.title == "Jurassic Park I":
movie.plot = "An industrialist invites experts to visit his theme park of cloned dinosaurs. After a power failure," \
" the creatures run loose, putting everyone's lives, including his grandchildren's, in danger."
movie.save()

由于代码根据模型的 title 值执行第二个数据库操作,因此在ACID 事务错误时恢复更改可以防止进一步的数据不一致。

要学习;了解有关 DjangoACID 事务API 的更多信息,请参阅 Django 文档中的数据库事务。