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

事务和会话

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

在 MongoDB 中,事务在逻辑会话中运行。 会话是要按顺序运行的一组相关读取或写入操作。 会话为一组操作启用因果一致性,并允许您在符合 ACID 的事务中运行操作,这是一个满足原子性、一致性、隔离性和持久性预期的事务。 MongoDB 保证事务操作中涉及的数据保持一致,即使操作遇到意外错误。

使用MongoDB PHP库时,您可以从MongoDB\Client实例创建新会话。 然后,您可以使用生成的MongoDB\Driver\Session实例来执行事务。

警告

仅在创建SessionClient上运行的操作中使用 。 将Session与不同的Client一起使用会导致操作错误。

MongoDB在某些客户端会话中实现因果一致性。因果一致性模型ACID 一致性保证在分布式系统中,会话中的操作按因果顺序运行。客户端观察到的结果与因果关系或操作之间的依赖关系一致。示例,如果您执行一系列操作,其中一个操作在逻辑上依赖于另一个操作的结果,则任何后续读取都会反映这种依赖关系。

为了保证因果一致性,客户端端会话必须满足以下要求:

  • 启动会话时,驱动程序必须启用因果一致性选项。该选项默认启用。

  • 操作必须在单个线程的单个会话中运行。否则,会话或线程必须相互传达optime和集群时间值。 要查看传达这些值的两个会话的示例,请参阅MongoDB Server手册中的因果一致性示例

  • 您必须使用 majority读关注(read concern)。

  • 您必须使用 majority写关注(write concern)。这是默认的写关注(write concern)值。

下表描述了因果一致会话提供的ACID 一致性保证:

保证
说明

读取写入操作

读取操作会反映之前写入操作的结果。

单调读取

读取操作不会返回反映比先前读取操作更早的数据状态的结果。

单调写入

如果写入操作必须先于其他写入操作,则服务器会先运行此写入操作。

示例,如果调用 MongoDB\Collection::insertOne() 插入文档,然后调用 MongoDB\Collection::updateOne() 修改插入的文档,则服务器首先运行插入操作。

读取后写入

如果写入操作必须在其他读取操作之后执行,服务器会先执行读取操作。

示例,如果您调用 MongoDB\Collection::findOne() 来检索文档,然后调用 MongoDB\Collection::deleteOne() 来删除检索到的文档,则服务器会先运行查找操作。

提示

要学习;了解有关本节中提到的概念的更多信息,请参阅以下MongoDB Server手册条目:

在本节中,您可以学习;了解MongoDB PHP库提供的ACID 事务API。 在开始ACID 事务之前,必须在Client实例上使用MongoDB\Client::startSession()方法创建Session 。 然后,您可以使用以下任一 API 来执行ACID 事务:

MongoDB PHP库提供了一个便捷事务 API来管理ACID 事务生命周期。 通过使用MongoDB\with_transaction()函数在ACID 事务中运行自定义回调来实施此API 。 with_transaction()函数执行以下任务:

  • 启动ACID 事务

  • 通过结束ACID 事务或重试来处理错误,例如当操作返回 TransientTransactionError

  • 提交ACID 事务

本指南的事务示例部分演示了如何使用此API来执行ACID 事务。

或者,您可以使用Session类提供的方法更好地控制ACID 事务生命周期。 下表描述了这些方法:

方法
说明

startTransaction()

在此会话上启动新ACID 事务。必须将会话传递到ACID 事务内的每个操作中,否则操作将在ACID 事务外运行。您可以通过传递选项参数来设立ACID

事务选项。

commitTransaction()

提交此会话的ACID 事务。如果会话没有活动ACID 事务、ACID 事务先前已结束或者存在写冲突(write conflict),则此方法将返回错误。

abortTransaction()

结束此会话的活动事务。 如果该会话没有活动事务或者事务已提交或结束,则此方法将返回错误。

此示例定义了一个回调函数,用于修改bank数据库集合中银行ACID 事务的数据。 该代码执行以下操作:

  • 创建Collection实例以访问权限目标集合。

  • 指定帐号和账户之间转账的金额。

  • 定义回调函数,该函数接收Session实例作为参数。

  • 更新客户余额以反映转账情况。

  • 记录带有时间戳的ACID 事务收据。

  • 如果ACID 事务提交成功,则打印一条消息。

$receipts = $client->bank->receipts;
$checking = $client->bank->checking_accounts;
$saving = $client->bank->saving_accounts;
$accountId = '5678';
$transferAmount = 1000.0;
$callback = function (MongoDB\Driver\Session $session) use (
$checking,
$saving,
$receipts,
$accountId,
$transferAmount,
): void {
$checking->updateOne(
['account_id' => $accountId],
['$inc' => ['balance' => -$transferAmount]],
['session' => $session],
);
$saving->updateOne(
['account_id' => $accountId],
['$inc' => ['balance' => $transferAmount]],
['session' => $session],
);
$summary = sprintf('SAVINGS +%1$u CHECKING -%1$u', $transferAmount);
$receipts->insertOne(
[
'account_id' => $accountId,
'summary' => $summary,
'timestamp' => new MongoDB\BSON\UTCDateTime(),
],
['session' => $session],
);
echo 'Successfully performed transaction!', PHP_EOL;
echo 'Summary: ', $summary, PHP_EOL;
};

然后,运行以下代码以执行ACID 事务。 此代码完成以下操作:

  1. 使用startSession()方法从客户端创建会话。

  2. 调用with_transaction()函数来管理ACID 事务,并将会话和回调作为参数传递。

$session = $client->startSession();
try {
MongoDB\with_transaction($session, $callback);
} catch (MongoDB\Driver\Exception\RuntimeException $e) {
echo 'Caught exception: ', $e->getMessage(), PHP_EOL;
}
Successfully performed transaction!
Summary: SAVINGS +1000 CHECKING -1000

注意

不支持并行操作

PHP库不支持在单个ACID 事务中运行并行操作。

如果您使用的是PHP库 v2.1 或更高版本以及MongoDB Server v8.0 或更高版本,则可以使用 MongoDB\Client::bulkWrite() 方法在单个ACID 事务中对多个命名空间执行写入操作。有关更多信息,请参阅批量写入操作。

要学习;了解有关本指南中提到的概念的更多信息,请参阅MongoDB Server手册中的以下页面:

要学习;了解有关ACID compliance的更多信息,请参阅什么是数据库管理系统中的ACID属性? MongoDB网站上的文章。

要了解有关插入操作的更多信息,请参阅插入文档指南。

要进一步了解本指南所提及的方法和类型,请参阅以下 API 文档:

要学习;了解有关Session类和方法的详情,请参阅以下PHP扩展API文档: