对于 AI 代理:可在 https://www.mongodb.com/zh-cn/docs/llms.txt 获取文档索引—通过在任何 URL 路径后添加 .md 可获取所有页面的 Markdown 版本。
Make the MongoDB docs better! We value your opinion. Share your feedback for a chance to win $100.
MongoDB Branding Shape
Click here >
Docs 菜单

事务

在本指南中,您可以学习;了解如何使用MongoDB C++驱动程序来执行事务。事务允许您运行一系列操作,这些操作在提交ACID 事务之前不会更改任何数据。如果ACID 事务中的任何操作返回错误,驱动程序就会取消ACID 事务,并在所有数据更改变得可见之前将其丢弃。

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

使用C++驱动程序时,您可以从 mongocxx::client实例创建新会话。然后,您可以使用生成的 mongocxx::client_session实例来执行事务。我们建议您将客户端重复用于多个会话和事务,而不是每次都实例化一个新客户端。

警告

仅将 mongocxx::client_session 与创建它的 mongocxx::client 一起使用。 将 client_session 与不同的 client 一起使用会导致操作错误。

重要

mongocxx::client 的实例不是线程安全的。 每个 mongoxcc::client实例及其子实例(包括 mongocxx::client_session)一次应由一个线程使用。 要学习;了解更多信息,请参阅 Thread and Fork 安全指南。

MongoDB C++驱动程序提供了 Callback API和 Core API来管理ACID 事务方式。 在开始ACID 事务之前,必须调用 start_session() 方法来实例化 mongocxx::client_session。 然后,您可以使用以下任一 API 来执行ACID 事务:

  • Callback API :管理ACID 事务生命周期并自动包含错误处理逻辑的高级API 。

  • 核心API :低级API ,允许您管理ACID 事务的生命周期并实现自定义错误处理逻辑。

提示

要学习;了解有关错误处理的更多信息,请参阅MongoDB Server手册中的事务错误处理部分。

使用回调API以允许MongoDB C++驱动程序管理ACID 事务的生命周期。 要实现此API,请对 mongocxx::client_session 调用 with_transaction() 方法,并传入回调函数,指定要运行的操作序列。 with_transaction() 方法启动ACID 事务,执行回调函数,并提交ACID 事务或结束ACID 事务(如果遇到错误)。 如果ACID 事务遇到 TransientTransactionErrorUnknownTransactionCommitResult 错误,则 with_transaction() 方法会重新运行ACID 事务。

以下代码使用 Callback API执行ACID 事务,将文档插入到 sample_mflix数据库的 moviescomments 集合中。 此代码执行以下操作:

  1. 使用 start_session() 方法从客户端启动会话。

  2. 定义回调函数,指定ACID 事务期间要执行的操作。

  3. 创建一个选项对象以准备为ACID 事务操作设立写关注(write concern)。 要学习;了解有关读取和写入语义的更多信息,请参阅MongoDB Server手册中的读关注/写关注/读取偏好部分。

  4. 调用 with_transaction() 方法来管理ACID 事务,并将回调函数和选项对象作为参数传递。

// Establish a connection to the MongoDB deployment
mongocxx::instance instance{};
mongocxx::client client(mongocxx::uri{"<connectionString>"});
// Define database and collection variables
auto db = client["sample_mflix"];
auto movies_collection = db["movies"];
auto comments_collection = db["comments"];
// Define a callback specifying the sequence of operations to perform during the transaction
mongocxx::client_session::with_transaction_cb callback = [&](mongocxx::client_session* session) {
// Important:: You must pass the session to the operations.
movies_collection.insert_one(*session, make_document(kvp("title", "Parasite")));
comments_collection.insert_one(*session, make_document(kvp("name", "Anjali Patel"),
kvp("text", "This is my new favorite movie!")));
};
// Define an options instance to explicitly set the write concern for the transaction operations
mongocxx::options::transaction opts;
mongocxx::write_concern wc;
wc.acknowledge_level(mongocxx::write_concern::level::k_majority);
opts.write_concern(wc);
// Start a client session
auto session = client.start_session();
try {
// Start a transaction, execute the operations in the callback function, and commit the results
session.with_transaction(callback, opts);
} catch (const mongocxx::exception& e) {
std::cout << "An exception occurred: " << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;

使用 Core API管理ACID 事务的生命周期。 要实现此API,您必须显式调用 mongocxx::client_session 接口中的方法来启动ACID 事务、提交活动ACID 事务以及在发生错误时结束ACID 事务。 Core API不会自动包含错误处理逻辑,而是允许您对包括 TransientTransactionErrorUnknownTransactionCommitResult 在内的错误实现自定义处理逻辑。

下表描述了 mongocxx::client_session 接口提供的 Core API方法:

方法
说明

start_transaction()

在当前客户端会话上启动新ACID 事务。接受可选的mongocxx::options::transaction 实例作为参数来设立选项。有关选项的完整列表,请参阅API文档中的 mongocxx::options:: ACID 事务 。如果选项配置错误、存在网络或其他暂时性故障或者存在其他错误(例如存在正在进行的ACID 事务的会话),则会引发异常。如果返回带有

TransientTransactionError标签的错误,您可以结束ACID

事务,然后重试并期望事务会成功。要学习;了解有关此方法的更多信息,请参阅MongoDB Server手册中的 startTransaction()指南。

commit_transaction()

在当前客户端会话上提交ACID 事务事务。如果选项配置错误、存在网络或其他暂时性故障或者存在其他错误(例如会话中没有正在进行的ACID

事务) ,则会引发异常。如果返回带有UnknownTransactionCommitResult 标签的错误,则可以结束ACID 事务,然后重试,期望在已提交的ACID 事务满足设立的写关注(write

concern)时成功。要学习;了解有关此方法的更多信息,请参阅MongoDB Server手册中的 commitTransaction()指南。

abort_transaction()

结束当前客户端会话上的ACID 事务。如果选项配置错误或存在其他错误(例如会话中没有正在进行的ACID

事务)

,则引发异常。要学习;了解有关此方法的更多信息,请参阅MongoDB Server手册中的 abortTransaction()指南。

提示

mongocxx::client_session 类还提供检索和修改会话属性的方法。要学习;了解更多信息,请参阅API文档中的 mongocxx::client_session

以下代码使用 Core API执行ACID 事务,将文档插入到 sample_mflix数据库的 moviescomments 集合中。 此代码执行以下操作:

  1. 使用 start_session() 方法从客户端启动会话。

  2. 创建一个选项对象以准备为ACID 事务操作设立写关注(write concern)。 要学习;了解有关读取和写入语义的更多信息,请参阅MongoDB Server手册中的读关注/写关注/读取偏好部分。

  3. 调用 start_transaction() 方法启动ACID 事务,并将选项对象作为参数传入。

  4. 运行操作以将文档插入到 sample_mflix数据库的集合中,并将活动会话传递给每个操作。 如果操作遇到错误,整个ACID 事务将中止。 如果错误具有标签 TransientTransactionError,则会重试ACID 事务。

  5. 使用 commit_transaction() 方法提交ACID 事务。 如果提交遇到标签为 UnknownTransactionCommitResult 的错误,则会重试提交。

// Establish a connection to the MongoDB deployment
mongocxx::instance instance{};
mongocxx::client client(mongocxx::uri{"<connectionString>"});
// Runs the txn_func and retries if TransientTransactionError occurs
using transaction_func = std::function<void(mongocxx::client_session& session)>;
auto run_with_retry = [](transaction_func txn_func,
mongocxx::client_session& session) {
while (true) {
try {
txn_func(session); // performs transaction.
break;
} catch (const mongocxx::operation_exception& oe) {
std::cout << "Transaction aborted. Caught exception during transaction."
<< std::endl;
// If transient error, retry the whole transaction.
if (oe.has_error_label("TransientTransactionError")) {
std::cout << "TransientTransactionError, retrying transaction..."
<< std::endl;
continue;
} else {
throw oe;
}
}
}
};
// Commits the active transaction and retries commit if UnknownTransactionCommitResult occurs
auto commit_with_retry = [](mongocxx::client_session& session) {
while (true) {
try {
session.commit_transaction(); // Uses write concern set at transaction start.
std::cout << "Transaction committed."
<< std::endl;
break;
} catch (const mongocxx::operation_exception& oe) {
// Can retry commit
if (oe.has_error_label("UnknownTransactionCommitResult")) {
std::cout << "UnknownTransactionCommitResult, retrying commit..."
<< std::endl;
continue;
} else {
std::cout << "Error during commit..."
<< std::endl;
throw oe;
}
}
}
};
auto txn_func = [&](mongocxx::client_session& session) {
auto& client = session.client();
// Define database and collection variables
auto db = client["sample_mflix"];
auto movies_collection = db["movies"];
auto comments_collection = db["comments"];
// Define an options instance to explicitly set the write concern for the transaction operations
mongocxx::options::transaction opts;
mongocxx::write_concern wc;
wc.acknowledge_level(mongocxx::write_concern::level::k_majority);
opts.write_concern(wc);
session.start_transaction(opts);
// Attempt to insert documents into database collections
try {
movies_collection.insert_one(session, make_document(kvp("title", "Parasite")));
comments_collection.insert_one(session, make_document(kvp("name", "Anjali Patel"),
kvp("text", "This is my new favorite movie!")));
} catch (const mongocxx::operation_exception& oe) {
std::cout << "Caught exception during transaction, aborting."
<< std::endl;
session.abort_transaction();
throw oe;
}
commit_with_retry(session);
};
// Start a client session
auto session = client.start_session();
try {
run_with_retry(txn_func, session);
} catch (const mongocxx::operation_exception& oe) {
// Do something with error
throw oe;
}

要进一步学习;了解本指南中讨论的概念,请参阅MongoDB Server手册中的以下页面:

要学习;了解有关ACID合规性的更多信息,请参阅MongoDB网站上的《数据库管理系统中的ACID属性》指南。

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

要进一步了解本指南所讨论的任何类型或方法,请参阅以下 API 文档: