From cb0cf8025a712e5aed991f5978b2ff3519643920 Mon Sep 17 00:00:00 2001 From: Jordan Smith Date: Thu, 15 Aug 2024 10:22:30 -0700 Subject: [PATCH 1/7] first draft transactions page --- .../write/transactions/transactions.java | 53 +++++++ source/write-data-to-mongo.txt | 1 + source/write/transactions.txt | 133 ++++++++++++++++++ 3 files changed, 187 insertions(+) create mode 100644 source/includes/write/transactions/transactions.java create mode 100644 source/write/transactions.txt diff --git a/source/includes/write/transactions/transactions.java b/source/includes/write/transactions/transactions.java new file mode 100644 index 00000000..ff834fe2 --- /dev/null +++ b/source/includes/write/transactions/transactions.java @@ -0,0 +1,53 @@ +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.reactivestreams.client.MongoClient; +import com.mongodb.reactivestreams.client.MongoClients; +import com.mongodb.reactivestreams.client.MongoCollection; +import com.mongodb.reactivestreams.client.MongoDatabase; +import org.bson.Document; +import reactor.core.publisher.Mono; + +public class TransactionExample { + public static void main(String[] args) { + String uri = ""; + + MongoClientSettings settings = MongoClientSettings.builder() + .applyConnectionString(new ConnectionString(uri)) + .build(); + + try { + MongoClient mongoClient = MongoClients.create(settings); + + MongoDatabase restaurantsDatabase = mongoClient.getDatabase("sample_restaurants"); + MongoCollection restaurants = restaurantsDatabase.getCollection("restaurants"); + MongoDatabase moviesDatabase = mongoClient.getDatabase("sample_mflix"); + MongoCollection movies = moviesDatabase.getCollection("movies"); + + Mono.from(mongoClient.startSession()) + .flatMap(session -> { + // Begins the transaction + session.startTransaction(); + + // Inserts documents in the given order + return Mono + .from(restaurants.insertOne(session, + new Document("name", "Reactive Streams Pizza").append("cuisine", "Pizza"))) + .then(Mono.from(movies.insertOne(session, + new Document("title", "Java: Into the Streams").append("type", "Movie")))) + // Commits the transaction + .flatMap(result -> Mono.from(session.commitTransaction()) + .thenReturn(result)) + .onErrorResume(error -> Mono.from(session.abortTransaction()).then(Mono.error(error))) + .doFinally(signalType -> session.close()); + }) + // Closes the client after the transaction completes + .doFinally(signalType -> mongoClient.close()) + // Prints the results of the transaction + .subscribe( + result -> System.out.println("Transaction succeeded"), + error -> System.err.println("Transaction failed: " + error)); + } catch (Exception e) { + System.err.println("An error occurred: " + e.getMessage()); + } + } +} diff --git a/source/write-data-to-mongo.txt b/source/write-data-to-mongo.txt index 5729eb2b..2fdbc348 100644 --- a/source/write-data-to-mongo.txt +++ b/source/write-data-to-mongo.txt @@ -27,6 +27,7 @@ Write Data to MongoDB /write/replace-documents /write/write-delete-documents /write/bulk-writes + /write/transactions /write/store-large-docs /write/write-concern /write/command diff --git a/source/write/transactions.txt b/source/write/transactions.txt new file mode 100644 index 00000000..38f38b96 --- /dev/null +++ b/source/write/transactions.txt @@ -0,0 +1,133 @@ +.. _java-rs-transactions: + +============ +Transactions +============ + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: ACID, bulk write, code example + +Overview +-------- + +In this guide, you can learn how to use the {+driver-short+} to perform +**transactions**. Transactions allow you to run a series of operations that do +not apply until all data changes are successful. If any operation in the +transaction fails, the driver cancels the transaction and discards all data +changes without ever becoming visible. + +In MongoDB, transactions run within logical **sessions**. A +session is a grouping of related +read or write operations that you intend to run sequentially. With sessions, you can +enable :manual:`causal consistency +` for a +group of operations, and run :website:`ACID transactions +`. MongoDB guarantees that the data involved in your +transaction operations remains consistent, even if the operations encounter +unexpected errors. + +When using the {+driver-short+}, you can create a new session from a ``MongoClient`` +instance as a ``ClientSession`` type. We recommend that you reuse your client for +multiple sessions and transactions instead of instantiating a new client each +time. + +.. warning:: + + Use a ``ClientSession`` only with the ``MongoClient`` (or associated + ``MongoDatabase`` or ``MongoCollection``) that created it. Using a ``ClientSession`` with + a different ``MongoClient`` results in operation errors. + +Sample Data +~~~~~~~~~~~ + +The examples in this guide use the ``sample_restaurants.restaurants`` and ``sample_mflix.movies`` collections +from the :atlas:`Atlas sample datasets `. To learn how to create a +free MongoDB Atlas cluster and load the sample datasets, see the +:ref:``. + +.. include:: includes/reactor-note.rst + +Transaction Methods +------------------- + +Create a ``ClientSession`` by using the ``startSession()`` method on your ``MongoClient`` +instance. You can then modify the session state by using the methods provided by +the ``ClientSession``. The following table details the methods you can use to +manage your transaction: + +.. list-table:: + :widths: 40 60 + :header-rows: 1 + + * - Method + - Description + + * - ``startTransaction()`` + - | Starts a new transaction, configured with the given options, on + this session. Throws an exception if there is already + a transaction in progress for the session. To learn more about + this method, see the :manual:`startTransaction() page + ` in the {+mdb-server+} manual. + + * - ``abortTransaction()`` + - | Ends the active transaction for this session. Throws an exception + if there is no active transaction for the session or if the + transaction is already committed or ended. To learn more about + this method, see the :manual:`abortTransaction() page + ` in the {+mdb-server+} manual. + + * - ``commitTransaction()`` + - | Commits the active transaction for this session. Throws an exception + if there is no active transaction for the session or if the + transaction was ended. To learn more about + this method, see the :manual:`commitTransaction() page + ` in the {+mdb-server+} manual. + +Transaction Example +------------------- + +The following example demonstrates how to create a session, create a +transaction, and insert documents into multiple collections in one transaction. +The code completes the following steps: + +- Creates a session from the client by using the ``startSession()`` method +- Starts a transaction by using the ``startTransaction()`` method +- Inserts documents into the ``restaurants`` and ``movies`` collections +- Commits the transaction by using the ``commitTransaction()`` method + +.. literalinclude:: /includes/write/transactions/transactions.java + :language: java + :copyable: + :emphasize-lines: 26, 29, 33-36, 38 + +Additional Information +---------------------- + +To learn more about the concepts mentioned in this guide, see the +following pages in the Server manual: + +- :manual:`Transactions ` +- :manual:`Server Sessions ` +- :manual:`Read Isolation, Consistency, and Recency ` + +API Documentation +~~~~~~~~~~~~~~~~~ + +To learn more about any of the types or methods discussed in this +guide, see the following API Documentation: + +- `MongoClient <{+api+}mongodb-driver-reactivestreams/com/mongodb/reactivestreams/client/MongoClient.html>`__ +- `startSession() <{+api+}/mongodb-driver-reactivestreams/com/mongodb/reactivestreams/client/MongoClient.html#startSession()>`__ +- `startTransaction() <{+api+}/mongodb-driver-reactivestreams/com/mongodb/reactivestreams/client/ClientSession.html#startTransaction()>`__ +- `abortTransaction() <{+api+}/mongodb-driver-reactivestreams/com/mongodb/reactivestreams/client/ClientSession.html#abortTransaction()>`__ +- `commitTransaction() <{{+api+}/mongodb-driver-reactivestreams/com/mongodb/reactivestreams/client/ClientSession.html#commitTransaction()>`__ From 81b3eeed35c5f63a799c9fc57663d57eef71c54c Mon Sep 17 00:00:00 2001 From: Jordan Smith Date: Thu, 15 Aug 2024 12:50:01 -0700 Subject: [PATCH 2/7] typos --- source/write/transactions.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/write/transactions.txt b/source/write/transactions.txt index 38f38b96..7bf48ff7 100644 --- a/source/write/transactions.txt +++ b/source/write/transactions.txt @@ -118,7 +118,7 @@ following pages in the Server manual: - :manual:`Transactions ` - :manual:`Server Sessions ` -- :manual:`Read Isolation, Consistency, and Recency ` +- :manual:`Causal Consistency ` API Documentation ~~~~~~~~~~~~~~~~~ @@ -126,8 +126,8 @@ API Documentation To learn more about any of the types or methods discussed in this guide, see the following API Documentation: -- `MongoClient <{+api+}mongodb-driver-reactivestreams/com/mongodb/reactivestreams/client/MongoClient.html>`__ +- `MongoClient <{+api+}/mongodb-driver-reactivestreams/com/mongodb/reactivestreams/client/MongoClient.html>`__ - `startSession() <{+api+}/mongodb-driver-reactivestreams/com/mongodb/reactivestreams/client/MongoClient.html#startSession()>`__ - `startTransaction() <{+api+}/mongodb-driver-reactivestreams/com/mongodb/reactivestreams/client/ClientSession.html#startTransaction()>`__ - `abortTransaction() <{+api+}/mongodb-driver-reactivestreams/com/mongodb/reactivestreams/client/ClientSession.html#abortTransaction()>`__ -- `commitTransaction() <{{+api+}/mongodb-driver-reactivestreams/com/mongodb/reactivestreams/client/ClientSession.html#commitTransaction()>`__ +- `commitTransaction() <{+api+}/mongodb-driver-reactivestreams/com/mongodb/reactivestreams/client/ClientSession.html#commitTransaction()>`__ From 17fe4b3f1dec618df4d86efc723f8181556a1982 Mon Sep 17 00:00:00 2001 From: Jordan Smith Date: Thu, 15 Aug 2024 12:51:05 -0700 Subject: [PATCH 3/7] meta --- source/write/transactions.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/write/transactions.txt b/source/write/transactions.txt index 7bf48ff7..c5f766e8 100644 --- a/source/write/transactions.txt +++ b/source/write/transactions.txt @@ -15,7 +15,7 @@ Transactions :values: reference .. meta:: - :keywords: ACID, bulk write, code example + :keywords: ACID, write, consistency, code example Overview -------- From 2ddcb614f38c29ce686510aa24ec4cdee8566174 Mon Sep 17 00:00:00 2001 From: Jordan Smith Date: Thu, 15 Aug 2024 13:22:14 -0700 Subject: [PATCH 4/7] feedback --- .../write/transactions/transactions.java | 81 +++++++------------ source/write/transactions.txt | 12 +-- 2 files changed, 37 insertions(+), 56 deletions(-) diff --git a/source/includes/write/transactions/transactions.java b/source/includes/write/transactions/transactions.java index ff834fe2..49b3eb91 100644 --- a/source/includes/write/transactions/transactions.java +++ b/source/includes/write/transactions/transactions.java @@ -1,53 +1,34 @@ -import com.mongodb.ConnectionString; -import com.mongodb.MongoClientSettings; -import com.mongodb.reactivestreams.client.MongoClient; -import com.mongodb.reactivestreams.client.MongoClients; -import com.mongodb.reactivestreams.client.MongoCollection; -import com.mongodb.reactivestreams.client.MongoDatabase; -import org.bson.Document; -import reactor.core.publisher.Mono; +try { + MongoClient mongoClient = MongoClients.create(settings); -public class TransactionExample { - public static void main(String[] args) { - String uri = ""; + MongoDatabase restaurantsDatabase = mongoClient.getDatabase("sample_restaurants"); + MongoCollection restaurants = restaurantsDatabase.getCollection("restaurants"); + MongoDatabase moviesDatabase = mongoClient.getDatabase("sample_mflix"); + MongoCollection movies = moviesDatabase.getCollection("movies"); - MongoClientSettings settings = MongoClientSettings.builder() - .applyConnectionString(new ConnectionString(uri)) - .build(); + Mono.from(mongoClient.startSession()) + .flatMap(session -> { + // Begins the transaction + session.startTransaction(); - try { - MongoClient mongoClient = MongoClients.create(settings); - - MongoDatabase restaurantsDatabase = mongoClient.getDatabase("sample_restaurants"); - MongoCollection restaurants = restaurantsDatabase.getCollection("restaurants"); - MongoDatabase moviesDatabase = mongoClient.getDatabase("sample_mflix"); - MongoCollection movies = moviesDatabase.getCollection("movies"); - - Mono.from(mongoClient.startSession()) - .flatMap(session -> { - // Begins the transaction - session.startTransaction(); - - // Inserts documents in the given order - return Mono - .from(restaurants.insertOne(session, - new Document("name", "Reactive Streams Pizza").append("cuisine", "Pizza"))) - .then(Mono.from(movies.insertOne(session, - new Document("title", "Java: Into the Streams").append("type", "Movie")))) - // Commits the transaction - .flatMap(result -> Mono.from(session.commitTransaction()) - .thenReturn(result)) - .onErrorResume(error -> Mono.from(session.abortTransaction()).then(Mono.error(error))) - .doFinally(signalType -> session.close()); - }) - // Closes the client after the transaction completes - .doFinally(signalType -> mongoClient.close()) - // Prints the results of the transaction - .subscribe( - result -> System.out.println("Transaction succeeded"), - error -> System.err.println("Transaction failed: " + error)); - } catch (Exception e) { - System.err.println("An error occurred: " + e.getMessage()); - } - } -} + // Inserts documents in the given order + return Mono + .from(restaurants.insertOne(session, + new Document("name", "Reactive Streams Pizza").append("cuisine", "Pizza"))) + .then(Mono.from(movies.insertOne(session, + new Document("title", "Java: Into the Streams").append("type", "Movie")))) + // Commits the transaction + .flatMap(result -> Mono.from(session.commitTransaction()) + .thenReturn(result)) + .onErrorResume(error -> Mono.from(session.abortTransaction()).then(Mono.error(error))) + .doFinally(signalType -> session.close()); + }) + // Closes the client after the transaction completes + .doFinally(signalType -> mongoClient.close()) + // Prints the results of the transaction + .subscribe( + result -> System.out.println("Transaction succeeded"), + error -> System.err.println("Transaction failed: " + error)); +} catch (Exception e) { + System.err.println("An error occurred: " + e.getMessage()); +} \ No newline at end of file diff --git a/source/write/transactions.txt b/source/write/transactions.txt index c5f766e8..e7b93713 100644 --- a/source/write/transactions.txt +++ b/source/write/transactions.txt @@ -7,7 +7,7 @@ Transactions .. contents:: On this page :local: :backlinks: none - :depth: 1 + :depth: 2 :class: singlecol .. facet:: @@ -98,12 +98,12 @@ Transaction Example The following example demonstrates how to create a session, create a transaction, and insert documents into multiple collections in one transaction. -The code completes the following steps: +The code executes the following steps: -- Creates a session from the client by using the ``startSession()`` method -- Starts a transaction by using the ``startTransaction()`` method -- Inserts documents into the ``restaurants`` and ``movies`` collections -- Commits the transaction by using the ``commitTransaction()`` method +1. Creates a session from the client by using the ``startSession()`` method +* Starts a transaction by using the ``startTransaction()`` method +* Inserts documents into the ``restaurants`` and ``movies`` collections +* Commits the transaction by using the ``commitTransaction()`` method .. literalinclude:: /includes/write/transactions/transactions.java :language: java From de0dcf42194b0c136536f36283c7b22774569dda Mon Sep 17 00:00:00 2001 From: Jordan Smith Date: Thu, 15 Aug 2024 13:23:36 -0700 Subject: [PATCH 5/7] fix list --- source/write/transactions.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/write/transactions.txt b/source/write/transactions.txt index e7b93713..3aa637b8 100644 --- a/source/write/transactions.txt +++ b/source/write/transactions.txt @@ -101,9 +101,9 @@ transaction, and insert documents into multiple collections in one transaction. The code executes the following steps: 1. Creates a session from the client by using the ``startSession()`` method -* Starts a transaction by using the ``startTransaction()`` method -* Inserts documents into the ``restaurants`` and ``movies`` collections -* Commits the transaction by using the ``commitTransaction()`` method +#. Starts a transaction by using the ``startTransaction()`` method +#. Inserts documents into the ``restaurants`` and ``movies`` collections +#. Commits the transaction by using the ``commitTransaction()`` method .. literalinclude:: /includes/write/transactions/transactions.java :language: java From 0a41f08ec151c704c46a70b3d32e635387d6a5c2 Mon Sep 17 00:00:00 2001 From: Jordan Smith Date: Thu, 15 Aug 2024 13:24:21 -0700 Subject: [PATCH 6/7] trim code more --- .../write/transactions/transactions.java | 59 +++++++++---------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/source/includes/write/transactions/transactions.java b/source/includes/write/transactions/transactions.java index 49b3eb91..86c65f94 100644 --- a/source/includes/write/transactions/transactions.java +++ b/source/includes/write/transactions/transactions.java @@ -1,34 +1,31 @@ -try { - MongoClient mongoClient = MongoClients.create(settings); - MongoDatabase restaurantsDatabase = mongoClient.getDatabase("sample_restaurants"); - MongoCollection restaurants = restaurantsDatabase.getCollection("restaurants"); - MongoDatabase moviesDatabase = mongoClient.getDatabase("sample_mflix"); - MongoCollection movies = moviesDatabase.getCollection("movies"); +MongoClient mongoClient = MongoClients.create(settings); - Mono.from(mongoClient.startSession()) - .flatMap(session -> { - // Begins the transaction - session.startTransaction(); +MongoDatabase restaurantsDatabase = mongoClient.getDatabase("sample_restaurants"); +MongoCollection restaurants = restaurantsDatabase.getCollection("restaurants"); +MongoDatabase moviesDatabase = mongoClient.getDatabase("sample_mflix"); +MongoCollection movies = moviesDatabase.getCollection("movies"); - // Inserts documents in the given order - return Mono - .from(restaurants.insertOne(session, - new Document("name", "Reactive Streams Pizza").append("cuisine", "Pizza"))) - .then(Mono.from(movies.insertOne(session, - new Document("title", "Java: Into the Streams").append("type", "Movie")))) - // Commits the transaction - .flatMap(result -> Mono.from(session.commitTransaction()) - .thenReturn(result)) - .onErrorResume(error -> Mono.from(session.abortTransaction()).then(Mono.error(error))) - .doFinally(signalType -> session.close()); - }) - // Closes the client after the transaction completes - .doFinally(signalType -> mongoClient.close()) - // Prints the results of the transaction - .subscribe( - result -> System.out.println("Transaction succeeded"), - error -> System.err.println("Transaction failed: " + error)); -} catch (Exception e) { - System.err.println("An error occurred: " + e.getMessage()); -} \ No newline at end of file +Mono.from(mongoClient.startSession()) + .flatMap(session -> { + // Begins the transaction + session.startTransaction(); + +// Inserts documents in the given order +return Mono + .from(restaurants.insertOne(session, + new Document("name", "Reactive Streams Pizza").append("cuisine", "Pizza"))) + .then(Mono.from(movies.insertOne(session, + new Document("title", "Java: Into the Streams").append("type", "Movie")))) + // Commits the transaction + .flatMap(result -> Mono.from(session.commitTransaction()) + .thenReturn(result)) + .onErrorResume(error -> Mono.from(session.abortTransaction()).then(Mono.error(error))) + .doFinally(signalType -> session.close()); +}) +// Closes the client after the transaction completes +.doFinally(signalType -> mongoClient.close()) +// Prints the results of the transaction +.subscribe( + result -> System.out.println("Transaction succeeded"), + error -> System.err.println("Transaction failed: " + error)); From ba1dee2c9d06224e09c74ffe16c270135dd49d50 Mon Sep 17 00:00:00 2001 From: Jordan Smith Date: Thu, 15 Aug 2024 13:27:58 -0700 Subject: [PATCH 7/7] fix code formatting --- .../write/transactions/transactions.java | 39 +++++++++---------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/source/includes/write/transactions/transactions.java b/source/includes/write/transactions/transactions.java index 86c65f94..39da369d 100644 --- a/source/includes/write/transactions/transactions.java +++ b/source/includes/write/transactions/transactions.java @@ -1,4 +1,3 @@ - MongoClient mongoClient = MongoClients.create(settings); MongoDatabase restaurantsDatabase = mongoClient.getDatabase("sample_restaurants"); @@ -8,24 +7,22 @@ Mono.from(mongoClient.startSession()) .flatMap(session -> { - // Begins the transaction - session.startTransaction(); + // Begins the transaction + session.startTransaction(); -// Inserts documents in the given order -return Mono - .from(restaurants.insertOne(session, - new Document("name", "Reactive Streams Pizza").append("cuisine", "Pizza"))) - .then(Mono.from(movies.insertOne(session, - new Document("title", "Java: Into the Streams").append("type", "Movie")))) - // Commits the transaction - .flatMap(result -> Mono.from(session.commitTransaction()) - .thenReturn(result)) - .onErrorResume(error -> Mono.from(session.abortTransaction()).then(Mono.error(error))) - .doFinally(signalType -> session.close()); -}) -// Closes the client after the transaction completes -.doFinally(signalType -> mongoClient.close()) -// Prints the results of the transaction -.subscribe( - result -> System.out.println("Transaction succeeded"), - error -> System.err.println("Transaction failed: " + error)); + // Inserts documents in the given order + return Mono.from(restaurants.insertOne(session, new Document("name", "Reactive Streams Pizza").append("cuisine", "Pizza"))) + .then(Mono.from(movies.insertOne(session, new Document("title", "Java: Into the Streams").append("type", "Movie")))) + // Commits the transaction + .flatMap(result -> Mono.from(session.commitTransaction()) + .thenReturn(result)) + .onErrorResume(error -> Mono.from(session.abortTransaction()).then(Mono.error(error))) + .doFinally(signalType -> session.close()); + }) + // Closes the client after the transaction completes + .doFinally(signalType -> mongoClient.close()) + // Prints the results of the transaction + .subscribe( + result -> System.out.println("Transaction succeeded"), + error -> System.err.println("Transaction failed: " + error) + ); \ No newline at end of file