-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
Copy pathSession.commitTransaction.txt
184 lines (134 loc) · 6.07 KB
/
Session.commitTransaction.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
===========================
Session.commitTransaction()
===========================
.. default-domain:: mongodb
.. contents:: On this page
:local:
:backlinks: none
:depth: 1
:class: singlecol
Definition
----------
.. method:: Session.commitTransaction()
Saves the changes made by the operations in the :ref:`multi-document
transaction <transactions>` and ends the transaction.
.. include:: /includes/transaction-support
``Session.commitTransaction()`` does not return a value.
.. |dbcommand| replace:: :dbcommand:`commitTransaction` command
.. include:: /includes/fact-mongosh-shell-method-alt
Compatibility
-------------
.. |command| replace:: method
This method is available in deployments hosted in the following environments:
.. include:: /includes/fact-environments-atlas-only.rst
.. include:: /includes/fact-environments-atlas-support-all.rst
.. include:: /includes/fact-environments-onprem-only.rst
Behavior
--------
Write Concern
~~~~~~~~~~~~~
When commiting the transaction, the session uses the write concern
specified at the transaction start. See
:method:`Session.startTransaction()`.
If you commit using :writeconcern:`"w: 1" <\<number\>>` write concern,
your transaction can be :doc:`rolled back during the failover process
</core/replica-set-rollbacks>`.
Atomicity
~~~~~~~~~
When a transaction commits, all data changes made in the transaction
are saved and visible outside the transaction. That is, a transaction
will not commit some of its changes while rolling back others.
.. include:: /includes/extracts/transactions-committed-visibility.rst
Retryable
~~~~~~~~~
If the commit operation encounters an error, MongoDB drivers retry the
commit operation a single time regardless of whether
:urioption:`retryWrites` is set to ``false``. For more information, see
:ref:`transactions-retry`.
Example
-------
Consider a scenario where as changes are made to an employee's record
in the ``hr`` database, you want to ensure that the ``events``
collection in the ``reporting`` database are in sync with the ``hr``
changes. That is, you want to ensure that these writes are done as a
single transaction, such that either both operations succeed or fail.
The ``employees`` collection in the ``hr`` database has the following
documents:
.. code-block:: javascript
{ "_id" : ObjectId("5af0776263426f87dd69319a"), "employee" : 3, "name" : { "title" : "Mr.", "name" : "Iba Ochs" }, "status" : "Active", "department" : "ABC" }
{ "_id" : ObjectId("5af0776263426f87dd693198"), "employee" : 1, "name" : { "title" : "Miss", "name" : "Ann Thrope" }, "status" : "Active", "department" : "ABC" }
{ "_id" : ObjectId("5af0776263426f87dd693199"), "employee" : 2, "name" : { "title" : "Mrs.", "name" : "Eppie Delta" }, "status" : "Active", "department" : "XYZ" }
The ``events`` collection in the ``reporting`` database has the
following documents:
.. code-block:: javascript
{ "_id" : ObjectId("5af07daa051d92f02462644a"), "employee" : 1, "status" : { "new" : "Active", "old" : null }, "department" : { "new" : "ABC", "old" : null } }
{ "_id" : ObjectId("5af07daa051d92f02462644b"), "employee" : 2, "status" : { "new" : "Active", "old" : null }, "department" : { "new" : "XYZ", "old" : null } }
{ "_id" : ObjectId("5af07daa051d92f02462644c"), "employee" : 3, "status" : { "new" : "Active", "old" : null }, "department" : { "new" : "ABC", "old" : null } }
The following example opens a transaction, updates an employee's status
to ``Inactive`` in the ``employees`` status and inserts a corresponding
document to the ``events`` collection, and commits the two operations
as a single transaction.
.. code-block:: javascript
// Runs the txnFunc and retries if TransientTransactionError encountered
function runTransactionWithRetry(txnFunc, session) {
while (true) {
try {
txnFunc(session); // performs transaction
break;
} catch (error) {
// If transient error, retry the whole transaction
if (error?.errorLabels?.includes("TransientTransactionError") ) {
print("TransientTransactionError, retrying transaction ...");
continue;
} else {
throw error;
}
}
}
}
// Retries commit if UnknownTransactionCommitResult encountered
function commitWithRetry(session) {
while (true) {
try {
session.commitTransaction(); // Uses write concern set at transaction start.
print("Transaction committed.");
break;
} catch (error) {
// Can retry commit
if (error?.errorLabels?.includes("UnknownTransactionCommitResult") ) {
print("UnknownTransactionCommitResult, retrying commit operation ...");
continue;
} else {
print("Error during commit ...");
throw error;
}
}
}
}
// Updates two collections in a transactions
function updateEmployeeInfo(session) {
employeesCollection = session.getDatabase("hr").employees;
eventsCollection = session.getDatabase("reporting").events;
session.startTransaction( { readConcern: { level: "snapshot" }, writeConcern: { w: "majority" } } );
try{
employeesCollection.updateOne( { employee: 3 }, { $set: { status: "Inactive" } } );
eventsCollection.insertOne( { employee: 3, status: { new: "Inactive", old: "Active" } } );
} catch (error) {
print("Caught exception during transaction, aborting.");
session.abortTransaction();
throw error;
}
commitWithRetry(session);
}
// Start a session.
session = db.getMongo().startSession( { readPreference: { mode: "primary" } } );
try{
runTransactionWithRetry(updateEmployeeInfo, session);
} catch (error) {
// Do something with error
} finally {
session.endSession();
}
.. seealso::
- :method:`Session.abortTransaction()`
- :method:`Session.commitTransaction()`