Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 18 additions & 9 deletions Guides/Transactions.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,22 @@ Transactions in the driver must be started on a `ClientSession` using `startTran

## Examples

Below are some basic examples of using transactions in `MongoSwift`. In realistic use cases, transactions would ideally be retried when facing transient errors. For more detailed examples featuring retry logic, see the [official MongoDB documentation's examples](https://docs.mongodb.com/manual/core/transactions-in-applications/#txn-core-api).

### Transaction that Atomically Moves a `Document` from One `MongoCollection` to Another

The transaction below atomically deletes the document `{ "hello": "world" }` from the collection `test.src` and inserts the document in the collection `test.dest`. This ensures that the document exists in either `test.src` or `test.dest`, but not both or neither. Executing the delete and insert non-atomically raises the following issues:
- A race between `deleteOne()` and `insertOne()` where the document does not exist in either collection.
- If `deleteOne()` fails and `insertOne()` succeeds, the document exists in both collections.
- If `deleteOne()` succeeds and `insertOne()` fails, the document does not exist in either collection.

In order to achieve the highest safety guarantees that MongoDB transactions offer, a "snapshot" read concern and a "majority" write concern must be used. To see the varying levels safety provided by different read concern / write concern configurations, see the [official MongoDB documentation](https://docs.mongodb.com/manual/core/transactions/#read-concern-write-concern-read-preference).

Transactions will inherit the read concern / write concern / read preference specified on the client that started the transaction's session unless they were also specified in either the default transaction options or in the transaction options passed to `startTransaction`. See the below sections on how to do either.

**Note:** All operations executed as part of a transaction will use the transaction's read concern / write concern / read preference. Any of those options specified on the database or collection that executes the operation or on a per-operation basis will be _ignored_.
```swift
let client = try MongoClient(using: elg)
let client = try MongoClient(using: elg, options: ClientOptions(readConcern: .snapshot, writeConcern: .majority))
let session = client.startSession()

let db = client.db("test")
Expand All @@ -43,9 +50,9 @@ The default transaction options specified below apply to any transaction started
```swift
let txnOpts = TransactionOptions(
maxCommitTimeMS: 30,
readConcern: ReadConcern(.local),
readPreference: .primaryPreferred,
writeConcern: try WriteConcern(w: .majority)
readConcern: .snapshot,
readPreference: .primary,
writeConcern: .majority
)

let client = try MongoClient(using: elg)
Expand All @@ -63,17 +70,17 @@ session.startTransaction().flatMap { _ in

### Transaction with Custom Transaction Options

**Note**:: Any transaction options provided directly to `startTransaction()` override the default transaction options for the session. More so, the default transaction options for the session override any options inherited from the client.
**Note**: Any transaction options provided directly to `startTransaction()` override the default transaction options for the session. More so, the default transaction options for the session override any options inherited from the client.

```swift
let client = try MongoClient(using: elg)
let session = client.startSession()

let txnOpts = TransactionOptions(
maxCommitTimeMS: 30,
readConcern: ReadConcern(.local),
readPreference: .primaryPreferred,
writeConcern: try WriteConcern(w: .majority)
readConcern: .snapshot,
readPreference: .primary,
writeConcern: .majority
)

session.startTransaction(options: txnOpts).flatMap { _ in
Expand All @@ -87,4 +94,6 @@ session.startTransaction(options: txnOpts).flatMap { _ in
```

## See Also
- [MongoDB Transactions documentation](https://docs.mongodb.com/manual/core/transactions/)
- [MongoDB Transactions documentation](https://docs.mongodb.com/manual/core/transactions/)
- [MongoDB Driver Transactions Core API](https://docs.mongodb.com/manual/core/transactions-in-applications/#txn-core-api)
- [MongoDB Transactions and Read Concern / Write Concern / Read Preference](https://docs.mongodb.com/manual/core/transactions/#read-concern-write-concern-read-preference)
16 changes: 12 additions & 4 deletions Sources/MongoSwift/ClientSession.swift
Original file line number Diff line number Diff line change
Expand Up @@ -340,10 +340,18 @@ public final class ClientSession {
}

/**
* Starts a multi-document transaction for all subsequent operations in this session. Any options provided in
* `options` override the default transaction options for this session and any options inherited from
* `MongoClient`. The transaction must be completed with `commitTransaction` or `abortTransaction`. An in-progress
* transaction is automatically aborted when `ClientSession.end()` is called.
* Starts a multi-document transaction for all subsequent operations in this session.
*
* Any options provided in `options` will override the default transaction options for this session and any options
* inherited from `MongoClient`.
*
* Operations executed as part of the transaction will use the options specified on the transaction, and those
* options cannot be overridden at a per-operation level. Any options that overlap with the transaction options
* which can be specified at a per operation level (e.g. write concern) _will be ignored_ if specified. This
* includes options specified at the database or collection level on the object used to execute an operation.
*
* The transaction must be completed with `commitTransaction` or `abortTransaction`. An in-progress transaction is
* automatically aborted when `ClientSession.end()` is called.
*
* - Parameters:
* - options: The options to use when starting this transaction
Expand Down
5 changes: 5 additions & 0 deletions Sources/MongoSwift/Operations/StartSessionOperation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ public struct ClientSessionOptions {
public var causalConsistency: Bool?

/// The default `TransactionOptions` to use for transactions started on this session.
///
/// These may be overridden by options provided directly to `ClientSession.startTransaction`.
///
/// If this option is not specified, the options will be inherited from the client that started this session where
/// applicable (e.g. write concern).
public var defaultTransactionOptions: TransactionOptions?

/// Convenience initializer allowing any/all parameters to be omitted.
Expand Down
16 changes: 12 additions & 4 deletions Sources/MongoSwiftSync/ClientSession.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,18 @@ public final class ClientSession {
}

/**
* Starts a multi-document transaction for all subsequent operations in this session. Any options provided in
* `options` override the default transaction options for this session and any options inherited from
* `MongoClient`. The transaction must be completed with `commitTransaction` or `abortTransaction`. An in-progress
* transaction is automatically aborted when `ClientSession` goes out of scope.
* Starts a multi-document transaction for all subsequent operations in this session.
*
* Any options provided in `options` will override the default transaction options for this session and any options
* inherited from `MongoClient`.
*
* Operations executed as part of the transaction will use the options specified on the transaction, and those
* options cannot be overridden at a per-operation level. Any options that overlap with the transaction options
* which can be specified at a per operation level (e.g. write concern) _will be ignored_ if specified. This
* includes options specified at the database or collection level on the object used to execute an operation.
*
* The transaction must be completed with `commitTransaction` or `abortTransaction`. An in-progress transaction is
* automatically aborted when `ClientSession.end()` is called.
*
* - Parameters:
* - options: The options to use when starting this transaction
Expand Down