Skip to content

Commit c7013a9

Browse files
committed
DOCSP-30555: transactions guide (#87)
(cherry picked from commit 0542362)
1 parent 831a2fe commit c7013a9

File tree

5 files changed

+244
-4
lines changed

5 files changed

+244
-4
lines changed

source/fundamentals.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Fundamentals
1818
/fundamentals/schema-validation
1919
/fundamentals/aggregation
2020
/fundamentals/indexes
21+
/fundamentals/transactions
2122
/fundamentals/time-series
2223
/fundamentals/tracing-logging
2324
/fundamentals/run-command
@@ -29,7 +30,6 @@ Fundamentals
2930

3031
..
3132
Connect to MongoDB Atlas from AWS Lambda <https://www.mongodb.com/docs/atlas/manage-connections-aws-lambda/>
32-
/fundamentals/transactions
3333
/fundamentals/gridfs
3434
/fundamentals/encrypt-fields
3535

source/fundamentals/crud/compound-operations.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@ This guide includes the following sections:
4848
provides links to resources and API documentation for types
4949
and methods mentioned in this guide
5050

51-
.. TODO .. tip::
51+
.. tip::
5252

53-
.. If you must perform atomic read and writes on more than one
54-
.. document, use :ref:`transactions <rust-transactions>`.
53+
To learn how to perform atomic read and write operations on more than one
54+
document at a time, see the :ref:`rust-transactions` guide.
5555

5656
.. _rust-compound-sample-data:
5757

source/fundamentals/transactions.txt

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
.. _rust-transactions:
2+
3+
============
4+
Transactions
5+
============
6+
7+
.. facet::
8+
:name: genre
9+
:values: reference
10+
11+
.. meta::
12+
:keywords: code example, ACID compliance, multi-document
13+
14+
.. contents:: On this page
15+
:local:
16+
:backlinks: none
17+
:depth: 2
18+
:class: singlecol
19+
20+
Overview
21+
--------
22+
23+
In this guide, you can learn how to use the {+driver-short+} to perform
24+
**transactions**. Transactions allow you to perform a series of operations
25+
that change data only if the entire transaction is committed.
26+
If any operation in the transaction does not succeed, the driver stops the
27+
transaction and discards all data changes before they ever become
28+
visible. This feature is called **atomicity**.
29+
30+
In MongoDB, transactions run within logical sessions. A
31+
session is a grouping of related read or write operations that you
32+
want to run sequentially. Sessions enable causal consistency for a group
33+
of operations and allow you to run operations in an **ACID-compliant**
34+
transaction, which is a transaction that meets an expectation of
35+
atomicity, consistency, isolation, and durability. MongoDB guarantees
36+
that the data involved in your transaction operations remains
37+
consistent, even if the operations encounter unexpected errors.
38+
39+
When using the {+driver-short+}, you can create a new session from a
40+
``Client`` instance as a ``ClientSession`` type. You can improve your
41+
app's performance by reusing your client for multiple sessions and
42+
transactions instead of instantiating a new client each time.
43+
44+
.. warning::
45+
46+
Use a ``ClientSession`` only in operations running on the
47+
``Client`` that created it. Using a ``ClientSession`` with a
48+
different ``Client`` results in operation errors.
49+
50+
Methods
51+
-------
52+
53+
Create a ``ClientSession`` by using the ``start_session()`` method on your
54+
``Client`` instance. You can then modify the session state using the
55+
methods provided by the ``ClientSession`` type. The following table
56+
describes these methods:
57+
58+
.. list-table::
59+
:widths: 25 75
60+
:stub-columns: 1
61+
:header-rows: 1
62+
63+
* - Method
64+
- Description
65+
66+
* - ``start_transaction()``
67+
- | Starts a new transaction, configured according to an optional
68+
``TransactionOptions`` parameter, on this session. The session
69+
must be passed into each operation within the transaction, or
70+
the operation will run outside of the transaction.
71+
|
72+
| Errors returned from operations run within the transaction
73+
might include a ``TRANSIENT_TRANSACTION_ERROR`` label, which
74+
indicates that the entire transaction can be ended, then retried
75+
with the expectation that it will succeed.
76+
|
77+
| **Parameter**: ``TransactionOptions``
78+
79+
* - ``commit_transaction()``
80+
- | Commits the active transaction for this session. This method returns an
81+
error if there is no active transaction for the session or the
82+
transaction was previously ended.
83+
|
84+
| This method might return an error that includes an
85+
``UNKNOWN_TRANSACTION_COMMIT_RESULT`` label, which
86+
indicates that it is unknown if the committed transaction
87+
satisfies the set write concern. If you encounter this error,
88+
it is safe to retry the commit until the write concern is
89+
satisfied or the method returns an error without the label.
90+
91+
* - ``abort_transaction()``
92+
- | Ends the active transaction for this session. This method returns an
93+
error if there is no active transaction for the session or if the
94+
transaction was committed or ended.
95+
96+
* - ``with_transaction()``
97+
- | Starts a transaction on this session and runs the given
98+
callback, then commits or ends the transaction. When you use
99+
this method to perform a transaction, the driver automatically
100+
handles any errors, so you can choose to omit error handling code.
101+
|
102+
| Because the callback returns a future and can be run multiple
103+
times, the Rust language closure borrowing rules for captured
104+
values can be restrictive. So, the ``with_transaction()``
105+
method accepts a context parameter that is passed to the callback.
106+
|
107+
| **Parameters**: context ``C``, callback ``FnMut(&'a mut
108+
ClientSession, &'a mut C)``, ``TransactionOptions``
109+
110+
.. important:: Methods That Can Run in Transactions
111+
112+
To run MongoDB tasks within transactions, you must use the
113+
``_with_session()`` suffixed methods. These methods accept a
114+
``ClientSession`` instance as a parameter.
115+
116+
For example, to delete a document, you can generally use the
117+
``delete_one()`` method. However, to delete a document within
118+
a transaction, you must use the ``delete_one_with_session()``
119+
method and pass the session as a parameter.
120+
121+
Example
122+
-------
123+
124+
The following code defines the ``insert_media()`` callback function that
125+
inserts data into the ``books`` and ``films`` collections:
126+
127+
.. literalinclude:: /includes/fundamentals/code-snippets/transaction.rs
128+
:language: rust
129+
:dedent:
130+
:start-after: begin-callback
131+
:end-before: end-callback
132+
133+
The following code completes the following actions to perform the
134+
transaction:
135+
136+
1. Creates a session from the client by using the ``start_session()`` method.
137+
#. Uses the ``with_transaction()`` method to start a transaction and run
138+
the ``insert_media()`` callback function within the transaction.
139+
140+
.. io-code-block::
141+
142+
.. input:: /includes/fundamentals/code-snippets/transaction.rs
143+
:language: rust
144+
:dedent:
145+
:start-after: begin-session
146+
:end-before: end-session
147+
148+
.. output::
149+
:language: console
150+
:visible: false
151+
152+
Successfully committed transaction!
153+
154+
If you require more control over your transactions, see the `ClientSession API
155+
documentation <{+api+}/struct.ClientSession.html#transactions>`__
156+
to find an example that shows how to manually create and commit a transaction.
157+
158+
Additional Information
159+
----------------------
160+
161+
To learn more about the concepts mentioned in this guide, see the
162+
following pages in the Server manual:
163+
164+
- :manual:`Transactions </core/transactions/>`
165+
- :manual:`Server Sessions </reference/server-sessions/>`
166+
- :manual:`Read Isolation, Consistency, and Recency </core/read-isolation-consistency-recency/#causal-consistency>`
167+
168+
To learn more about ACID compliance, see the :website:`What are ACID
169+
Properties in Database Management Systems? </basics/acid-transactions>`
170+
article on the MongoDB website.
171+
172+
To learn more about insert operations, see the
173+
:ref:`rust-insert-guide` guide.
174+
175+
API Documentation
176+
~~~~~~~~~~~~~~~~~
177+
178+
To learn more about the methods and types mentioned in this
179+
guide, see the following API documentation:
180+
181+
- `ClientSession <{+api+}/struct.ClientSession.html#>`__
182+
- `start_session() <{+api+}/struct.Client.html#method.start_session>`__
183+
- `start_transaction() <{+api+}/struct.ClientSession.html#method.start_transaction>`__
184+
- `commit_transaction() <{+api+}/struct.ClientSession.html#method.commit_transaction>`__
185+
- `abort_transaction() <{+api+}/struct.ClientSession.html#method.abort_transaction>`__
186+
- `with_transaction() <{+api+}/struct.ClientSession.html#method.with_transaction>`__
187+
- `TransactionOptions <{+api+}/options/struct.TransactionOptions.html>`__

source/includes/fundamentals-sections.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Fundamentals section:
1111
- :ref:`Implement Schema Validation <rust-schema-validation>`
1212
- :ref:`Perform Aggregations <rust-aggregation>`
1313
- :ref:`Create and Manage Indexes <rust-indexes>`
14+
- :ref:`Perform a Multi-Document Transaction <rust-transactions>`
1415
- :ref:`Create a Time Series Collection <rust-time-series>`
1516
- :ref:`Record Driver Events <rust-tracing-logging>`
1617
- :ref:`Run A Database Command <rust-run-command>`
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
use std::env;
2+
use bson::{ Document, doc };
3+
use futures::FutureExt;
4+
use mongodb::{ Client, ClientSession };
5+
use mongodb::error::Error;
6+
7+
// begin-callback
8+
async fn insert_media(session: &mut ClientSession) -> Result<(), Error> {
9+
let books_coll = session
10+
.client()
11+
.database("db")
12+
.collection::<Document>("books");
13+
14+
let films_coll = session
15+
.client()
16+
.database("db")
17+
.collection::<Document>("films");
18+
19+
books_coll.insert_one_with_session(
20+
doc! {
21+
"name": "Sula",
22+
"author": "Toni Morrison"
23+
},
24+
None,
25+
session
26+
).await?;
27+
28+
films_coll.insert_one_with_session(
29+
doc! { "name": "Nostalgia", "year": 1983 },
30+
None,
31+
session
32+
).await?;
33+
34+
Ok(())
35+
}
36+
// end-callback
37+
38+
#[tokio::main]
39+
async fn main() -> mongodb::error::Result<()> {
40+
let uri = "<connection string>";
41+
let client = Client::with_uri_str(uri).await?;
42+
43+
// begin-session
44+
let mut session = client.start_session(None).await?;
45+
session
46+
.with_transaction((), |session, _| insert_media(session).boxed(), None)
47+
.await?;
48+
println!("Successfully committed transaction!");
49+
// end-session
50+
51+
Ok(())
52+
}

0 commit comments

Comments
 (0)