From 7809afbd948b64c27387785c81bdb18f8c2d1b39 Mon Sep 17 00:00:00 2001 From: Stephanie Aurelio Date: Thu, 5 Sep 2024 14:45:17 -0700 Subject: [PATCH 01/10] add new page and code example --- source/includes/write/transaction.kt | 54 ++++++++++ source/write-operations.txt | 1 + source/write/transactions.txt | 149 +++++++++++++++++++++++++++ 3 files changed, 204 insertions(+) create mode 100644 source/includes/write/transaction.kt create mode 100644 source/write/transactions.txt diff --git a/source/includes/write/transaction.kt b/source/includes/write/transaction.kt new file mode 100644 index 00000000..47b935c7 --- /dev/null +++ b/source/includes/write/transaction.kt @@ -0,0 +1,54 @@ +import com.mongodb.* +import com.mongodb.client.ClientSession +import com.mongodb.client.MongoClients +import com.mongodb.client.MongoCollection +import org.bson.Document + +fun main() { +// start-transaction + // Creates a new MongoClient with a connection string + val client = MongoClients.create("") + + // Gets the database and collection + val restaurantsDb = client.getDatabase("sample_restaurants") + val restaurantsCollection: MongoCollection = restaurantsDb.getCollection("restaurants") + + fun insertDocuments(session: ClientSession) { + // Sets options for the collection operation within the transaction + val restaurantsCollectionWithOptions = restaurantsCollection + .withWriteConcern(WriteConcern("majority")) + .withReadConcern(ReadConcern.LOCAL) + + // Inserts documents within the transaction + restaurantsCollectionWithOptions.insertOne( + session, + Document("name", "Kotlin Sync Pizza").append("cuisine", "Pizza") + ) + restaurantsCollectionWithOptions.insertOne( + session, + Document("name", "Kotlin Sync Burger").append("cuisine", "Burger") + ) + } + + // Starts a client session + client.startSession().use { session -> + try { + val txnOptions = TransactionOptions.builder() + .readConcern(ReadConcern.LOCAL) + .writeConcern(WriteConcern.MAJORITY) + .build() + + // Use the withTransaction method to start a transaction and execute the lambda function + session.withTransaction({ + insertDocuments(session) + println("Transaction succeeded") + }, txnOptions) + } catch (e: Exception) { + println("Transaction failed: ${e.message}") + } + } + + // Closes the MongoClient + client.close() +// end-transaction +} \ No newline at end of file diff --git a/source/write-operations.txt b/source/write-operations.txt index 7760534f..19b7e693 100644 --- a/source/write-operations.txt +++ b/source/write-operations.txt @@ -27,6 +27,7 @@ Write Data to MongoDB /write/replace /write/delete /write/bulk-write + /write/transactions .. /write/gridfs diff --git a/source/write/transactions.txt b/source/write/transactions.txt new file mode 100644 index 00000000..ed9d41f4 --- /dev/null +++ b/source/write/transactions.txt @@ -0,0 +1,149 @@ +.. _kotlin-sync-write-transactions: + +============ +Transactions +============ + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: ACID, write, consistency, code example + +Overview +-------- + +In this guide, you can learn how to use the {+driver-short+} driver to perform +**transactions**. Transactions allow you to run a series of operations that do +not change any data until the transaction is committed. If any operation in +the transaction returns an error, the driver cancels the transaction and discards +all data changes before they ever become 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. Sessions enable **causal consistency** for a +group of operations and allow you to run operations in an +**ACID-compliant transaction**, which is a transaction that meets an expectation +of atomicity, consistency, isolation, and durability. 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 ``MongoClient`` for multiple sessions and transactions instead of +creating 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`` collection +from the :atlas:`Atlas sample datasets `. To learn how to create a +free MongoDB Atlas cluster and load the sample datasets, see the +:ref:`` tutorial. + + +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 describes the methods you can use to +manage your transaction: + +.. list-table:: + :widths: 25 75 + :header-rows: 1 + + * - Method + - Description + + * - ``startTransaction()`` + - | Starts a new transaction, configured with the given options, on + this session. Returns an error if there is already + a transaction in progress for the session. To learn more about + this method, see the :manual:`startTransaction() page + ` in the Server manual. + | + | **Parameter**: ``transactionOptions`` + + * - ``abortTransaction()`` + - | Ends the active transaction for this session. Returns an + error if there is no active transaction for the session or the + transaction has been committed or ended. To learn more about + this method, see the :manual:`abortTransaction() page + ` in the Server manual. + | + + * - ``commitTransaction()`` + - | Commits the active transaction for this session. Returns an + error 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 Server manual. + + * - ``withTransaction()`` + - | Starts a transaction on this session and runs the given function within + a transaction. + | + | **Parameters**: ``transactionBody, options`` + +Example +------- + +The following example demonstrates how to create a session, create a +transaction, and insert documents into multiple collections in one transaction +through the following steps: + +1. Create a session from the client by using the ``startSession()`` method. +#. Use the ``withTransaction()`` method to start a transaction. +#. Insert multiple documents. The ``withTransaction()`` method runs the + insert operation and commits the transaction. If any operation results in + errors, ``withTransaction()`` cancels the transaction. +#. Close the connection to the server by using the ``client.close()`` method. + +.. literalinclude:: /includes/write/transaction.kt + :start-after: start-transaction + :end-before: end-transaction + :language: kotlin + :copyable: + :dedent: + + +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 ` + +To learn more about ACID compliance, see the :website:`What are ACID +Properties in Database Management Systems? ` +article on the MongoDB website. + +.. _api-docs-transaction: + +API Documentation +~~~~~~~~~~~~~~~~~ + +To learn more about any of the types or methods discussed in this +guide, see the following API documentation: + +- `ClientSession <{+api+}/com.mongodb.kotlin.client/-client-session/index.html>`_ +- `abortTransaction() <{+api+}/com.mongodb.kotlin.client/-client-session/abort-transaction.html>`_ +- `commitTransaction() <{+api+}/com.mongodb.kotlin.client/-client-session/commit-transaction.html>`_ +- `startTransaction() <{+api+}/com.mongodb.kotlin.client/-client-session/start-transaction.html>`_ +- `withTransaction() <{+api+}/com.mongodb.kotlin.client/-client-session/with-transaction.html>`_ From 7380addd7f29e675b57b94942ba9716df67f2cfe Mon Sep 17 00:00:00 2001 From: Stephanie Aurelio Date: Fri, 6 Sep 2024 11:49:37 -0700 Subject: [PATCH 02/10] edits --- source/write/transactions.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/write/transactions.txt b/source/write/transactions.txt index ed9d41f4..f16e010d 100644 --- a/source/write/transactions.txt +++ b/source/write/transactions.txt @@ -20,7 +20,7 @@ Transactions Overview -------- -In this guide, you can learn how to use the {+driver-short+} driver to perform +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 change any data until the transaction is committed. If any operation in the transaction returns an error, the driver cancels the transaction and discards @@ -53,8 +53,10 @@ Sample Data The examples in this guide use the ``sample_restaurants.restaurants`` collection from the :atlas:`Atlas sample datasets `. To learn how to create a free MongoDB Atlas cluster and load the sample datasets, see the -:ref:`` tutorial. +:atlas:`Get Started with Atlas ` guide. +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 From 2272a23174d70365132581aaf685d859a6dd4b1c Mon Sep 17 00:00:00 2001 From: Stephanie Aurelio Date: Fri, 6 Sep 2024 13:12:13 -0700 Subject: [PATCH 03/10] update example section --- source/write/transactions.txt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/source/write/transactions.txt b/source/write/transactions.txt index f16e010d..e5439e25 100644 --- a/source/write/transactions.txt +++ b/source/write/transactions.txt @@ -109,9 +109,10 @@ through the following steps: 1. Create a session from the client by using the ``startSession()`` method. #. Use the ``withTransaction()`` method to start a transaction. -#. Insert multiple documents. The ``withTransaction()`` method runs the - insert operation and commits the transaction. If any operation results in - errors, ``withTransaction()`` cancels the transaction. +#. Insert multiple documents into the ``restaurants`` collection. The + ``withTransaction()`` method runs the insert operation and commits the + transaction. If any operation results in errors, ``withTransaction()`` + cancels the transaction. #. Close the connection to the server by using the ``client.close()`` method. .. literalinclude:: /includes/write/transaction.kt @@ -121,6 +122,9 @@ through the following steps: :copyable: :dedent: +If you require more control over your transactions, you can use the ``startTransaction()`` +method. You can use this method with the ``commitTransaction()`` and ``abortTransaction()`` +methods described in the preceding section to manually manage the transaction lifecycle. Additional Information ---------------------- From ba73ae2c9eef6564c074a58c98af9b5045b01d37 Mon Sep 17 00:00:00 2001 From: Stephanie Aurelio Date: Mon, 9 Sep 2024 11:10:31 -0700 Subject: [PATCH 04/10] update example --- source/includes/write/transaction.kt | 2 +- source/write/transactions.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/includes/write/transaction.kt b/source/includes/write/transaction.kt index 47b935c7..5035399c 100644 --- a/source/includes/write/transaction.kt +++ b/source/includes/write/transaction.kt @@ -38,7 +38,7 @@ fun main() { .writeConcern(WriteConcern.MAJORITY) .build() - // Use the withTransaction method to start a transaction and execute the lambda function + // Uses the withTransaction method to start a transaction and run the given function session.withTransaction({ insertDocuments(session) println("Transaction succeeded") diff --git a/source/write/transactions.txt b/source/write/transactions.txt index e5439e25..ee3dc1ca 100644 --- a/source/write/transactions.txt +++ b/source/write/transactions.txt @@ -104,7 +104,7 @@ Example ------- The following example demonstrates how to create a session, create a -transaction, and insert documents into multiple collections in one transaction +transaction, and insert documents into a collection in one transaction through the following steps: 1. Create a session from the client by using the ``startSession()`` method. From d57a4cf5230fbbfba9d3abc4f34a90b0783d7d43 Mon Sep 17 00:00:00 2001 From: Stephanie Aurelio Date: Tue, 10 Sep 2024 10:40:32 -0700 Subject: [PATCH 05/10] implement RR feedback --- source/includes/write/transaction.kt | 22 +++++++++++++--------- source/write/transactions.txt | 13 +++++++++++-- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/source/includes/write/transaction.kt b/source/includes/write/transaction.kt index 5035399c..97d14eff 100644 --- a/source/includes/write/transaction.kt +++ b/source/includes/write/transaction.kt @@ -1,32 +1,36 @@ import com.mongodb.* import com.mongodb.client.ClientSession import com.mongodb.client.MongoClients -import com.mongodb.client.MongoCollection import org.bson.Document +// start-data-class +data class Restaurant(val name: String, val cuisine: String) +// end-data-class + fun main() { // start-transaction // Creates a new MongoClient with a connection string val client = MongoClients.create("") // Gets the database and collection - val restaurantsDb = client.getDatabase("sample_restaurants") - val restaurantsCollection: MongoCollection = restaurantsDb.getCollection("restaurants") + val database = client.getDatabase("sample_restaurants") + val collection = database.getCollection("restaurants") - fun insertDocuments(session: ClientSession) { + // Defines options and inserts restaurants into the collection + fun insertRestaurantsInTransaction(session: ClientSession) { // Sets options for the collection operation within the transaction - val restaurantsCollectionWithOptions = restaurantsCollection + val restaurantsCollectionWithOptions = collection .withWriteConcern(WriteConcern("majority")) .withReadConcern(ReadConcern.LOCAL) - // Inserts documents within the transaction + // Inserts restaurants within the transaction restaurantsCollectionWithOptions.insertOne( session, - Document("name", "Kotlin Sync Pizza").append("cuisine", "Pizza") + Restaurant("name", "Kotlin Sync Pizza").append("cuisine", "Pizza") ) restaurantsCollectionWithOptions.insertOne( session, - Document("name", "Kotlin Sync Burger").append("cuisine", "Burger") + Restaurant("name", "Kotlin Sync Burger").append("cuisine", "Burger") ) } @@ -40,7 +44,7 @@ fun main() { // Uses the withTransaction method to start a transaction and run the given function session.withTransaction({ - insertDocuments(session) + insertRestaurantsInTransaction(session) println("Transaction succeeded") }, txnOptions) } catch (e: Exception) { diff --git a/source/write/transactions.txt b/source/write/transactions.txt index ee3dc1ca..6a1d5ba7 100644 --- a/source/write/transactions.txt +++ b/source/write/transactions.txt @@ -55,6 +55,15 @@ from the :atlas:`Atlas sample datasets `. To learn how to create a free MongoDB Atlas cluster and load the sample datasets, see the :atlas:`Get Started with Atlas ` guide. +The documents in this collection are modeled by the following {+language+} data class: + +.. literalinclude:: /includes/write/transaction.kt + :start-after: start-data-class + :end-before: end-data-class + :language: kotlin + :copyable: + :dedent: + Methods ------- @@ -77,7 +86,7 @@ manage your transaction: this method, see the :manual:`startTransaction() page ` in the Server manual. | - | **Parameter**: ``transactionOptions`` + | **Parameter**: ``TransactionOptions`` * - ``abortTransaction()`` - | Ends the active transaction for this session. Returns an @@ -98,7 +107,7 @@ manage your transaction: - | Starts a transaction on this session and runs the given function within a transaction. | - | **Parameters**: ``transactionBody, options`` + | **Parameters**: transaction body function, ``TransactionOptions`` Example ------- From f0b50af13fa9fe2ddf33e26a70ecbc7af90584d1 Mon Sep 17 00:00:00 2001 From: Stephanie Aurelio Date: Tue, 10 Sep 2024 11:34:04 -0700 Subject: [PATCH 06/10] update example references --- source/includes/write/transaction.kt | 16 ++++++---------- source/write/transactions.txt | 10 +++++----- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/source/includes/write/transaction.kt b/source/includes/write/transaction.kt index 97d14eff..94d08489 100644 --- a/source/includes/write/transaction.kt +++ b/source/includes/write/transaction.kt @@ -9,28 +9,24 @@ data class Restaurant(val name: String, val cuisine: String) fun main() { // start-transaction - // Creates a new MongoClient with a connection string + // Creates a new MongoClient to manage your connection val client = MongoClients.create("") // Gets the database and collection val database = client.getDatabase("sample_restaurants") val collection = database.getCollection("restaurants") - // Defines options and inserts restaurants into the collection + // Inserts restaurants into the collection fun insertRestaurantsInTransaction(session: ClientSession) { - // Sets options for the collection operation within the transaction - val restaurantsCollectionWithOptions = collection - .withWriteConcern(WriteConcern("majority")) - .withReadConcern(ReadConcern.LOCAL) // Inserts restaurants within the transaction - restaurantsCollectionWithOptions.insertOne( + collection.insertOne( session, - Restaurant("name", "Kotlin Sync Pizza").append("cuisine", "Pizza") + Restaurant("Kotlin Sync Pizza", "Pizza") ) - restaurantsCollectionWithOptions.insertOne( + collection.insertOne( session, - Restaurant("name", "Kotlin Sync Burger").append("cuisine", "Burger") + Restaurant("Kotlin Sync Burger", "Burger") ) } diff --git a/source/write/transactions.txt b/source/write/transactions.txt index 6a1d5ba7..a443d4d7 100644 --- a/source/write/transactions.txt +++ b/source/write/transactions.txt @@ -117,11 +117,11 @@ transaction, and insert documents into a collection in one transaction through the following steps: 1. Create a session from the client by using the ``startSession()`` method. -#. Use the ``withTransaction()`` method to start a transaction. -#. Insert multiple documents into the ``restaurants`` collection. The - ``withTransaction()`` method runs the insert operation and commits the - transaction. If any operation results in errors, ``withTransaction()`` - cancels the transaction. +#. Define the ``insertRestaurantsInTransaction`` method to insert multiple + documents into the ``restaurants`` collection. +#. Use the ``withTransaction()`` method to start a transaction. The ``withTransaction()`` + method runs the insert operation and commits the transaction. If any + operation results in errors, ``withTransaction()`` cancels the transaction. #. Close the connection to the server by using the ``client.close()`` method. .. literalinclude:: /includes/write/transaction.kt From fe1c19f5eefa920dfd04b85392be88378f35a955 Mon Sep 17 00:00:00 2001 From: Stephanie Aurelio Date: Tue, 10 Sep 2024 11:44:55 -0700 Subject: [PATCH 07/10] typo --- 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 a443d4d7..f0719507 100644 --- a/source/write/transactions.txt +++ b/source/write/transactions.txt @@ -117,7 +117,7 @@ transaction, and insert documents into a collection in one transaction through the following steps: 1. Create a session from the client by using the ``startSession()`` method. -#. Define the ``insertRestaurantsInTransaction`` method to insert multiple +#. Define the ``insertRestaurantsInTransaction()`` method to insert multiple documents into the ``restaurants`` collection. #. Use the ``withTransaction()`` method to start a transaction. The ``withTransaction()`` method runs the insert operation and commits the transaction. If any From a81cae4ecc4ffd51cfeefc866addc6b5dc2b93e8 Mon Sep 17 00:00:00 2001 From: Stephanie Aurelio Date: Tue, 10 Sep 2024 14:06:46 -0700 Subject: [PATCH 08/10] RR feedback --- source/includes/write/transaction.kt | 1 + source/write/transactions.txt | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/source/includes/write/transaction.kt b/source/includes/write/transaction.kt index 94d08489..2ba390b7 100644 --- a/source/includes/write/transaction.kt +++ b/source/includes/write/transaction.kt @@ -33,6 +33,7 @@ fun main() { // Starts a client session client.startSession().use { session -> try { + // Sets transaction options val txnOptions = TransactionOptions.builder() .readConcern(ReadConcern.LOCAL) .writeConcern(WriteConcern.MAJORITY) diff --git a/source/write/transactions.txt b/source/write/transactions.txt index f0719507..4772cd12 100644 --- a/source/write/transactions.txt +++ b/source/write/transactions.txt @@ -122,7 +122,7 @@ through the following steps: #. Use the ``withTransaction()`` method to start a transaction. The ``withTransaction()`` method runs the insert operation and commits the transaction. If any operation results in errors, ``withTransaction()`` cancels the transaction. -#. Close the connection to the server by using the ``client.close()`` method. +#. Close the connection to the server by using the ``MongoClient.close()`` method. .. literalinclude:: /includes/write/transaction.kt :start-after: start-transaction @@ -149,7 +149,7 @@ To learn more about ACID compliance, see the :website:`What are ACID Properties in Database Management Systems? ` article on the MongoDB website. -.. _api-docs-transaction: +.. _kotlin-sync-api-docs-transaction: API Documentation ~~~~~~~~~~~~~~~~~ From 49666abee6f81b3750301ae7409b20002a495518 Mon Sep 17 00:00:00 2001 From: Stephanie Aurelio Date: Thu, 26 Sep 2024 14:01:52 -0700 Subject: [PATCH 09/10] implement technical feedback --- source/includes/write/transaction.kt | 7 +++---- source/write/transactions.txt | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/source/includes/write/transaction.kt b/source/includes/write/transaction.kt index 2ba390b7..39f98aed 100644 --- a/source/includes/write/transaction.kt +++ b/source/includes/write/transaction.kt @@ -1,6 +1,5 @@ -import com.mongodb.* -import com.mongodb.client.ClientSession -import com.mongodb.client.MongoClients +import com.mongodb.kotlin.client.ClientSession +import com.mongodb.kotlin.client.MongoClient import org.bson.Document // start-data-class @@ -10,7 +9,7 @@ data class Restaurant(val name: String, val cuisine: String) fun main() { // start-transaction // Creates a new MongoClient to manage your connection - val client = MongoClients.create("") + val client = MongoClient.create("") // Gets the database and collection val database = client.getDatabase("sample_restaurants") diff --git a/source/write/transactions.txt b/source/write/transactions.txt index 4772cd12..f210f200 100644 --- a/source/write/transactions.txt +++ b/source/write/transactions.txt @@ -120,7 +120,7 @@ through the following steps: #. Define the ``insertRestaurantsInTransaction()`` method to insert multiple documents into the ``restaurants`` collection. #. Use the ``withTransaction()`` method to start a transaction. The ``withTransaction()`` - method runs the insert operation and commits the transaction. If any + method runs the insert operations and commits the transaction. If any operation results in errors, ``withTransaction()`` cancels the transaction. #. Close the connection to the server by using the ``MongoClient.close()`` method. From 6d149001c81fb59b4da4bc1591618cb3143657cc Mon Sep 17 00:00:00 2001 From: Stephanie Aurelio Date: Fri, 27 Sep 2024 08:04:02 -0700 Subject: [PATCH 10/10] update imports in example --- source/includes/write/transaction.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/includes/write/transaction.kt b/source/includes/write/transaction.kt index 39f98aed..e708b962 100644 --- a/source/includes/write/transaction.kt +++ b/source/includes/write/transaction.kt @@ -1,6 +1,9 @@ import com.mongodb.kotlin.client.ClientSession import com.mongodb.kotlin.client.MongoClient import org.bson.Document +import com.mongodb.ReadConcern +import com.mongodb.TransactionOptions +import com.mongodb.WriteConcern // start-data-class data class Restaurant(val name: String, val cuisine: String)