Transactions
Overview
In this guide, you can learn how to use the Rust driver to perform transactions. Transactions allow you to perform a series of operations that change data only if the entire transaction is committed. If any operation in the transaction does not succeed, the driver stops the transaction and discards all data changes before they ever become visible. This feature is called atomicity.
In MongoDB, transactions run within logical sessions. A session is a grouping of related read or write operations that you want to run sequentially. Sessions enable causal consistency for a group of operations and allow you to run 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 Rust driver, you can create a new session from a
Client
instance as a ClientSession
type. You can improve your
app's performance by reusing your client for multiple sessions and
transactions instead of instantiating a new client each time.
Warning
Use a ClientSession
only in operations running on the
Client
that created it. Using a ClientSession
with a
different Client
results in operation errors.
Methods
Create a ClientSession
by using the start_session()
method on your
Client
instance. You can then modify the session state using the
methods provided by the ClientSession
type. The following table
describes these methods:
Method | Description |
---|---|
| Starts a new transaction on this session. The session
must be passed into each operation within the transaction, or
the operation will run outside of the transaction. You can set transaction options by chaining TransactionOptions
option builder methods to start_transaction() .Errors returned from operations run within the transaction
might include a TRANSIENT_TRANSACTION_ERROR label, which
indicates that the entire transaction can be ended, then retried
with the expectation that it will succeed. |
| Commits the active transaction for this session. This method returns an
error if there is no active transaction for the session or the
transaction was previously ended. This method might return an error that includes an
UNKNOWN_TRANSACTION_COMMIT_RESULT label, which
indicates that it is unknown if the committed transaction
satisfies the set write concern. If you encounter this error,
it is safe to retry the commit until the write concern is
satisfied or the method returns an error without the label. |
| Ends the active transaction for this session. This method returns an
error if there is no active transaction for the session or if the
transaction was committed or ended. |
| Runs the given callback, then commits or ends the transaction. The
driver retries callbacks and commits that raise an error with a
TRANSIENT_TRANSACTION_ERROR label. If they raise any
other error, the driver ends the transaction and returns the error
to the caller. When you use this method to perform a transaction,
the driver automatically handles any errors, so you can choose to omit
error handling code.Because the callback returns a future and can be run multiple
times, the Rust language closure borrowing rules for captured
values can be restrictive. So, the and_run()
method accepts a context parameter that is passed to the callback.Parameters: context C , callback FnMut(&'a mut
ClientSession, &'a mut C) |
Important
Methods That Can Run in Transactions
To run MongoDB operations within transactions, you must chain the
session()
method to the operation. This method accepts a
ClientSession
instance as a parameter.
For example, to delete a document, you can generally use the
delete_one()
method. However, to delete a document within
a transaction, you must chain the session()
method to
delete_one()
and pass the session as a parameter.
Example
The following code defines the insert_media()
callback function that
inserts data into the books
and films
collections:
async fn insert_media(session: &mut ClientSession) -> Result<(), Error> { let books_coll = session .client() .database("db") .collection::<Document>("books"); let films_coll = session .client() .database("db") .collection::<Document>("films"); books_coll .insert_one(doc! { "name": "Sula", "author": "Toni Morrison" }) .session(&mut *session) .await?; films_coll .insert_one(doc! { "name": "Nostalgia", "year": 1983 }) .session(&mut *session) .await?; Ok(()) }
The following code completes the following actions to perform the transaction:
Creates a session from the client by using the
start_session()
method.Calls the
start_transaction()
method to start a transaction.Calls the
and_run()
method to run theinsert_media()
callback function within the transaction.
let mut session = client.start_session().await?; session .start_transaction() .and_run((), |session, _| insert_media(session).boxed()) .await?; println!("Successfully committed transaction!");
Successfully committed transaction!
If you require more control over your transactions, see the ClientSession API documentation to find an example that shows how to manually create and commit a transaction.
Note
Parallel Operations Not Supported
The Rust driver does not support running parallel operations within a single transaction.
If you're using MongoDB Server v8.0 or later, you can perform write operations on multiple namespaces within a single transaction by using bulk write operations. For more information, see the Bulk Operations guide.
Additional Information
To learn more about the concepts mentioned in this guide, see the following pages in the Server manual:
To learn more about ACID compliance, see the What are ACID Properties in Database Management Systems? article on the MongoDB website.
To learn more about insert operations, see the Insert Documents guide.
API Documentation
To learn more about the methods and types mentioned in this guide, see the following API documentation: