Skip to content

Commit 8071004

Browse files
committed
docs(transactions): add note about nested transactions
Fix #15079
1 parent 24f8fb9 commit 8071004

File tree

1 file changed

+44
-2
lines changed

1 file changed

+44
-2
lines changed

docs/transactions.md

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,22 @@ doc.isNew;
6363

6464
## Note About Parallelism in Transactions {#note-about-parallelism-in-transactions}
6565

66-
Running operations in parallel is **not supported** during a transaction. The use of `Promise.all`, `Promise.allSettled`, `Promise.race`, etc. to parallelize operations inside a transaction is
67-
undefined behaviour and should be avoided.
66+
Running operations in parallel is **not supported** during a transaction.
67+
The use of `Promise.all`, `Promise.allSettled`, `Promise.race`, etc. to parallelize operations inside a transaction is undefined behaviour and should be avoided.
68+
69+
MongoDB also does not support multiple transactions on the same session in parallel.
70+
This also means MongoDB does not support nested transactions on the same session.
71+
The following code will throw a `Transaction already in progress` error.
72+
73+
```javascript
74+
const doc = new Person({ name: 'Will Riker' });
75+
76+
await db.transaction(async function setRank(session) {
77+
// This throws `Transaction already in progress` because there is already a transaction
78+
// in progress for this session.
79+
await session.withTransaction(async () => {});
80+
});
81+
```
6882

6983
## With Mongoose Documents and `save()` {#with-mongoose-documents-and-save}
7084

@@ -116,6 +130,34 @@ await Test.exists({ _id: doc._id });
116130
With `transactionAsyncLocalStorage`, you no longer need to pass sessions to every operation.
117131
Mongoose will add the session by default under the hood.
118132

133+
`transactionAsyncLocalStorage` creates a new session each time you call `connection.transaction()`.
134+
This means each transaction will have its own session and be independent of other transactions.
135+
This also means that nested transactions are also independent of each other.
136+
137+
```javascript
138+
await mongoose.connection.transaction(async () => {
139+
await User.create({ name: 'John' });
140+
// This starts an independent transaction - this transaction will **NOT**
141+
// be rolled back even though it is within another `transaction()` call
142+
await mongoose.connection.transaction(async () => {
143+
await User.create({ name: 'Jane' });
144+
});
145+
throw new Error('Fail the top-level transaction');
146+
});
147+
```
148+
149+
However, if the nested transaction fails, the top-level transaction will still be rolled back because `await mongoose.connection.transaction()` throws.
150+
151+
```javascript
152+
await mongoose.connection.transaction(async () => {
153+
await User.create({ name: 'John' });
154+
await mongoose.connection.transaction(async () => {
155+
// This causes both transactions to roll back, but only because this error bubbles up.
156+
throw new Error('Fail the nested transaction');
157+
});
158+
});
159+
```
160+
119161
## Advanced Usage {#advanced-usage}
120162

121163
Advanced users who want more fine-grained control over when they commit or abort transactions

0 commit comments

Comments
 (0)