Docs Menu
Docs Home
/ / /
C++ Driver
/

Transactions

On this page

  • Overview
  • Transaction APIs
  • Callback API
  • Core API
  • Additional Information
  • API Documentation

In this guide, you can learn how to use the MongoDB C++ Driver to perform transactions. Transactions allow you to run a series of operations that do not change any data until the transaction is committed. If any operation in the transaction returns an error, the driver cancels the transaction and discards all data changes before they ever become visible.

In MongoDB, transactions run within logical sessions. A session is a grouping of related read or write operations that you intend to run sequentially. Sessions enable causal consistency for a group of operations in an ACID-compliant transaction, which is a transaction that meets an expectation of atomicity, consistency, isolation, and durability. MongoDB guarantees that the data involved in your transaction operations remains consistent, even if the operations encounter unexpected errors.

When using the C++ driver, you can create a new session from a mongocxx::client instance. Then, you can use the resulting mongocxx::client_session instance to perform transactions. We recommend that you reuse your client for multiple sessions and transactions instead of instantiating a new client each time.

Warning

Use a mongocxx::client_session only with the mongocxx::client that created it. Using a client_session with a different client results in operation errors.

Important

Instances of mongocxx::client are not thread-safe. Each mongoxcc::client instance and its child instances, including mongocxx::client_session, should be used by a single thread at a time. To learn more, see the Thread and Fork Safety guide.

The MongoDB C++ Driver provides a callback API and a core API to manage the transaction lifestyle. Before you begin a transaction, you must call the start_session() method to instantiate a mongocxx::client_session. Then, you can use either of the following APIs to perform a transaction:

  • Callback API: High-level API that manages the life cycle of the transaction and automatically incorporates error handling logic.

  • Core API: Low-level API that allows you to manage the life cycle of the transaction and implement custom error handling logic.

Tip

To learn more about error handling, see the Transaction Error Handling section in the MongoDB Server manual.

Use the callback API to allow the MongoDB C++ Driver to manage the life cycle of your transaction. To implement this API, call the with_transaction() method on your mongocxx::client_session and pass in a callback function specifying the sequence of operations you want to run. The with_transaction() method starts a transaction, executes the callback function, and either commits your transaction or ends the transaction if it encounters an error. If your transaction encounters a TransientTransactionError or UnknownTransactionCommitResult error, the with_transaction() method reruns the transaction.

The following code uses the callback API to perform a transaction that inserts documents into the movies and comments collections in the sample_mflix database. This code performs the following actions:

  1. Starts a session from the client using the start_session() method.

  2. Defines a callback function that specifies the operations to perform during the transaction.

  3. Creates an option object to prepare to set the write concern for the transaction operations. To learn more about read and write semantics, see the Read Concern/Write Concern/Read Preference section in the MongoDB Server manual.

  4. Calls the with_transaction() method to manage the transaction, passing the callback function and option object as arguments.

// 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;

Use the core API to manage the life cycle of your transaction. To implement this API, you must make explicit calls to methods in the mongocxx::client_session interface to start a transaction, commit an active transaction, and end a transaction if an error occurs. The core API doesn't automatically incorporate error handling logic, and instead allows you to implement custom handling logic for errors including TransientTransactionError and UnknownTransactionCommitResult.

The following table describes the core API methods provided by the mongocxx::client_session interface:

Method
Description

start_transaction()

Starts a new transaction on the current client session. Accepts an optional mongocxx::options::transaction instance as an argument to set options. For a full list of options, see mongocxx::options::transaction in the API documentation.

Raises an exception if the options are misconfigured, if there are network or other transient failures, or if there are other errors such as a session with a transaction already in progress. If an error is returned with the TransientTransactionError label, you can end the transaction and then retry it with the expectation that it will succeed.

To learn more about this method, see the startTransaction() guide in the MongoDB Server manual.

commit_transaction()

Commits the active transaction on the current client session.

Raises an exception if options are misconfigured, if there are network or other transient failures, or if there are other errors such as a session with no transaction in progress. If an error is returned with the UnknownTransactionCommitResult label, you can end the transaction and then retry it with the expectation that it will succeed when the committed transaction satisfies the set write concern.

To learn more about this method, see the commitTransaction() guide in the MongoDB Server manual.

abort_transaction()

Ends the active transaction on the current client session.

Raises an exception if the options are misconfigured or if there are other errors such as a session with no transaction in progress.

To learn more about this method, see the abortTransaction() guide in the MongoDB Server manual.

Tip

The mongocxx::client_session class also provides methods to retrieve and modify session properties. To learn more, see mongocxx::client_session in the API documentation.

The following code uses the core API to perform a transaction that inserts documents into the movies and comments collections in the sample_mflix database. This code performs the following actions:

  1. Starts a session from the client using the start_session() method.

  2. Creates an option object to prepare to set the write concern for the transaction operations. To learn more about read and write semantics, see the Read Concern/Write Concern/Read Preference section in the MongoDB Server manual.

  3. Calls the start_transaction() method to start a transaction, passing in the option object as an argument.

  4. Runs operations to insert documents into collections in the sample_mflix database, passing the active session to each operation. If an operation encounters an error, the whole transaction is aborted. If the error has the label TransientTransactionError, the transaction is retried.

  5. Commits the active transaction using the commit_transaction() method. If the commit encounters an error with the label UnknownTransactionCommitResult, the commit is retried.

// 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;
}

To learn more about the concepts discussed in this guide, see the following pages in the MongoDB Server manual:

To learn more about ACID complicance, see the ACID Properties in Database Management Systems guide on the MongoDB website.

To learn more about insert operations, see the Insert Documents guide.

To learn more about any of the types or methods discussed in this guide, see the following API Documentation:

Back

GridFS