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

事务

在本指南中,您可以了解如何使用 C 驱动程序执行事务。事务允许您执行一系列操作,这些操作仅在整个事务提交后才会更改数据。如果事务中的任何操作不成功,库就会停止事务,并在所有数据更改变得可见之前将其丢弃。这种功能称为原子性

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

使用C驱动程序时,您可以从 mongoc_client_t实例创建新会话。然后,您可以使用生成的 mongoc_client_session_t实例来执行事务。

警告

仅应将 mongoc_client_session_t 与创建它的 mongoc_client_t(或关联的 mongoc_database_tmongoc_collection_t)一起使用。将 mongoc_client_session_t 与其他 mongoc_client_t 一起使用会导致操作错误。

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

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

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

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

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

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

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

保证
说明

读取写入操作

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

单调读取

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

单调写入

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

示例,如果调用 mongoc_collection_insert_one() 插入文档,然后调用 mongoc_collection_update_one() 修改插入的文档,则服务器首先运行插入操作。

读取后写入

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

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

提示

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

在本节中,您可以了解 C 驱动程序提供的事务 API。在开始事务之前,您必须使用 mongoc_client_start_session() 函数在 mongoc_client_t 实例上创建 mongoc_client_session_t。然后,您可以使用以下任一 API 执行事务:

C 驱动程序提供了一个便捷事务 API 来管理事务生命周期。通过使用 mongoc_client_session_with_transaction() 函数实现此 API,以在事务中运行自定义回调。mongoc_client_session_with_transaction() 函数执行以下任务:

  • 启动ACID 事务

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

  • 提交ACID 事务

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

或者,您可以在 mongoc_client_session_t实例中使用以下函数,更好地控制ACID 事务生命周期:

function
说明

mongoc_client_session_start_transaction()

在该会话上启动使用给定选项配置的新事务。如果存在无效参数,则返回 false 并设置所提供的错误,例如已在进行中的事务会话。要了解有关此功能的更多信息,请参阅服务器手册中的 startTransaction() 页面

mongoc_client_session_abort_transaction()

终止此会话的活动事务。如果会话没有活动事务,或事务已提交或结束,则返回 false 并设置所提供的错误。要了解有关此功能的更多信息,请参阅服务器手册中的 abortTransaction() 页面

mongoc_client_session_commit_transaction()

提交此会话的活动事务。如果此会话没有活动事务或事务已结束,则返回错误。要了解有关此功能的更多信息,请参阅服务器手册中的commitTransaction() 页面

mongoc_client_session_destroy()

中止所有进行中的事务并结束此会话。释放与此会话相关的所有客户端资源。

mongoc_client_session_t要学习;了解有关检索 属性和修改可变会话属性的函数的更多信息,请参阅API文档。

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

  1. 定义回调函数,该函数接收mongoc_client_session_t实例作为参数。

  2. 创建mongoc_collection_t实例以访问权限目标集合。

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

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

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

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

bool
transaction_callback(mongoc_client_session_t *session, void *ctx, bson_t **reply,
bson_error_t *error)
{
BSON_UNUSED(ctx);
BSON_UNUSED(reply);
mongoc_client_t *client = mongoc_client_session_get_client(session);
mongoc_collection_t *checking = mongoc_client_get_collection(client, "sample_bank", "checking");
mongoc_collection_t *savings = mongoc_client_get_collection(client, "sample_bank", "savings");
mongoc_collection_t *receipts = mongoc_client_get_collection(client, "sample_bank", "receipts");
const char *account_id = "123456";
int transfer_amount = 1000;
bson_t *filter = BCON_NEW("account_id", BCON_UTF8(account_id));
bson_t *update_decrement = BCON_NEW("$inc", "{", "balance", BCON_INT32(-transfer_amount), "}");
bson_t *update_increment = BCON_NEW("$inc", "{", "balance", BCON_INT32(transfer_amount), "}");
if (!mongoc_collection_update_one(checking, filter, update_decrement, NULL, NULL, &error)) {
fprintf(stderr, "Failed to update checking account: %s\n", error.message);
return false;
}
if (!mongoc_collection_update_one(savings, filter, update_increment, NULL, NULL, &error)) {
fprintf(stderr, "Failed to update savings account: %s\n", error.message);
return false;
}
bson_t *receipt = BCON_NEW("account_id", BCON_UTF8(account_id),
"amount", BCON_INT32(transfer_amount),
"timestamp", BCON_DATE_TIME(bson_get_monotonic_time()));
if (!mongoc_collection_insert_one(receipts, receipt, NULL, NULL, &error)) {
fprintf(stderr, "Failed to insert receipt: %s\n", error.message);
return false;
}
mongoc_collection_destroy(checking);
mongoc_collection_destroy(savings);
mongoc_collection_destroy(receipts);
bson_destroy(filter);
bson_destroy(update_decrement);
bson_destroy(update_increment);
bson_destroy(receipt);
printf("Transaction successful!");
return true;
}

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

  1. 使用 mongoc_client_start_session() 函数从客户端创建会话。

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

mongoc_client_session_t *session = mongoc_client_start_session(client, NULL, NULL);
if (!session) {
fprintf(stderr, "Failed to start session\n");
mongoc_client_destroy(client);
return EXIT_FAILURE;
}
bool result =
mongoc_client_session_with_transaction(session,
(mongoc_client_session_with_transaction_cb_t) transaction_callback,
NULL, NULL, NULL, &error);
if (!result) {
fprintf(stderr, "Transaction error: %s\n", error.message);
}
mongoc_client_session_destroy(session);
mongoc_client_destroy(client);
mongoc_cleanup();
Transaction successful!

注意

不支持并行操作

C 驱动程序不支持在单个事务中运行并行操作。

如果您使用的是MongoDB Server v8.0 或更高版本,则可以使用批量写入操作在单个ACID 事务中对多个命名空间执行写入操作。有关更多信息,请参阅批量写入操作指南。

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

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

要学习;了解有关本指南中讨论的任何类型或函数的更多信息,请参阅以下API文档: