Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DOCSP-37469: Add transactions page #199

Merged
merged 5 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
2 changes: 2 additions & 0 deletions source/fundamentals.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Fundamentals
/fundamentals/bson
/fundamentals/specify-query
/fundamentals/serialization
/fundamentals/transactions
/fundamentals/logging
/fundamentals/encrypt-fields

Expand All @@ -36,5 +37,6 @@ Fundamentals
- :ref:`csharp-bson`
- :ref:`csharp-specify-query`
- :ref:`csharp-serialization`
- :ref:`csharp-transactions`
- :ref:`csharp-logging`
- :ref:`Encrypt Fields <csharp-fle>`
227 changes: 227 additions & 0 deletions source/fundamentals/transactions.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
.. _csharp-transactions:

============
Transactions
============

.. facet::
:name: genre
:values: reference

.. meta::
:keywords: code example, multi-document

.. contents:: On this page
:local:
:backlinks: none
:depth: 2
:class: singlecol

Overview
--------

In this guide, you can learn how to use the {+driver-long+} to perform
**transactions**. :manual:`Transactions </core/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
:manual:`session </reference/server-sessions/>` is a grouping of related
read or write operations that you intend to run sequentially. Sessions
enable :manual:`causal consistency
</core/read-isolation-consistency-recency/#causal-consistency>` for a
group of operations or allow you to execute operations in an
:website:`ACID transaction </basics/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 an ``IClientSession`` type. We recommend that you reuse
your client for multiple sessions and transactions instead of
instantiating a new client each time.

.. warning::

Use an ``IClientSession`` only with the ``MongoClient`` (or associated
``MongoDatabase`` or ``MongoCollection``) that created it. Using an
``IClientSession`` with a different ``MongoClient`` results in operation
errors.

Methods
-------

Create an ``IClientSession`` by using either the synchronous ``StartSession()`` or
the asynchronous ``StartSessionAsync()`` method on your ``MongoClient`` instance.
You can then modify the session state by using the method set
provided by the ``IClientSession`` interface. Select from the following
:guilabel:`Synchronous Methods` and :guilabel:`Asynchronous Methods`
tabs to learn about the methods to manage your transaction:

.. tabs::

.. tab:: Synchronous Methods
:tabid: synchronous-methods

.. 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
</reference/method/Session.startTransaction/>` in the Server manual.
|
| **Parameter**: ``TransactionOptions`` (optional)

* - ``AbortTransaction()``
- | Ends the active transaction for this session. Throws an exception
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
</reference/method/Session.abortTransaction/>` in the Server manual.
|
| **Parameter**: ``CancellationToken``

* - ``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
</reference/method/Session.commitTransaction/>` in the Server manual.
|
| **Parameter**: ``CancellationToken``

* - ``WithTransaction()``
- | Starts a transaction on this session and runs the given callback. To
learn more about this method, see the :manual:`withTransaction() page
</reference/method/Session.withTransaction/>` in the Server manual.

.. warning:: Handling Exceptions

When catching exceptions within the callback function used by
``WithTransaction()``, you **must** rethrow the exception before
exiting the try-catch block. Failing to do so can result in an
infinite loop. For further details on how to handle exceptions in this
case, see :manual:`Transactions </core/transactions/>` in the Server
manual and select :guilabel:`C#` from the language dropdown to view
the example.

|
| **Parameters**: ``Func <IClientSessionHandle, CancellationToken, Task<TResult>>``, ``TransactionOptions``, ``CancellationToken``
| **Return Type**: ``Task <TResult>``

.. tab:: Asynchronous Methods
:tabid: asynchronous-methods

.. 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
</reference/method/Session.startTransaction/>` in the Server manual.
|
| **Parameter**: ``TransactionOptions`` (optional)

* - ``AbortTransactionAsync()``
- | Ends the active transaction for this session. Throws an exception
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
</reference/method/Session.abortTransaction/>` in the Server manual.
|
| **Parameter**: ``CancellationToken``
| **Return Type**: ``Task``


* - ``CommitTransactionAsync()``
- | 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
</reference/method/Session.commitTransaction/>` in the Server manual.
|
| **Parameter**: ``CancellationToken``
| **Return Type**: ``Task``

* - ``WithTransactionAsync()``
- | Starts a transaction on this session and runs the given callback. To
learn more about this method, see the :manual:`withTransaction() page
</reference/method/Session.withTransaction/>` in the Server manual.

.. warning:: Handling Exceptions

When catching exceptions within the callback function used by
``WithTransactionAsync()``, you **must** rethrow the exception
before exiting the try-catch block. Failing to do so can result in an
infinite loop. For further details on how to handle exceptions in this
case, see :manual:`Transactions </core/transactions/>` in the Server
manual and select :guilabel:`C#` from the language dropdown to view
the example.

|
| **Parameters**: ``Func <IClientSessionHandle, CancellationToken, Task<TResult>>``, ``TransactionOptions``, ``CancellationToken``
| **Return Type**: ``Task <TResult>``

Example
-------

This example shows how you can create a session, create a
transaction, and insert documents into multiple collections within the transaction
through the following steps:

1. Create a session from the client by using the ``StartSession()`` method.
#. Use the ``StartTransaction()`` method to start a transaction.
#. Insert documents into the ``books`` and ``films`` collections.
#. Commit the transaction by using the ``CommitTransaction()`` method.

.. io-code-block::

.. input:: /includes/fundamentals/code-examples/Transaction.cs
:language: csharp
:dedent:
:start-after: begin-transaction
:end-before: end-transaction

.. output::
:language: console
:visible: false

Successfully committed transaction!

Additional Information
----------------------

To learn more about the concepts mentioned in this guide, see the
following pages in the Server manual:

- :manual:`Transactions </core/transactions/>`
- :manual:`Server Sessions </reference/server-sessions/>`
- :manual:`Read Isolation, Consistency, and Recency </core/read-isolation-consistency-recency/#causal-consistency>`

API Documentation
~~~~~~~~~~~~~~~~~

To learn more about any of the types or methods discussed in this
guide, see the following API Documentation:

- `IClientSession <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.IClientSession.html>`__
- `MongoClient <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.MongoClient.html>`__
- `StartTransaction() <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.IClientSession.StartTransaction.html>`__
- `AbortTransaction() <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.IClientSession.AbortTransaction.html>`__ / `AbortTransactionAsync() <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.IClientSession.AbortTransactionAsync.html>`__
- `CommitTransaction() <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.IClientSession.CommitTransaction.html>`__ / `CommitTransactionAsync() <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.IClientSession.CommitTransactionAsync.html>`__
- `WithTransaction() <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.IClientSession.WithTransaction.html>`__ / `WithTransactionAsync() <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.IClientSession.WithTransactionAsync.html>`__
- `TransactionOptions <{+new-api-root+}/MongoDB.Driver/MongoDB.Driver.TransactionOptions.html>`__
100 changes: 100 additions & 0 deletions source/includes/fundamentals/code-examples/Transaction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson.Serialization.Conventions;
using MongoDB.Driver;

public class BookTransaction
{
// Replace with your connection string
private const string MongoConnectionString = "<YOUR_CONNECTION_STRING>";

public static void Main(string[] args)
{
// Establishes the connection to MongoDB and accesses the library database
var mongoClient = new MongoClient(MongoConnectionString);
var database = mongoClient.GetDatabase("library");

// Cleans up the collections we'll be using
Setup(database);

// begin-transaction
var books = database.GetCollection<Book>("books");
var films = database.GetCollection<Film>("films");

// Begins transaction
using (var session = mongoClient.StartSession())
{
session.StartTransaction();

try
{
// Creates sample data
var book = new Book
{
Title = "Beloved",
Author = "Toni Morrison",
InStock = true
};

var film = new Film
{
Title = "Star Wars",
Director = "George Lucas",
InStock = true
};

// Inserts sample data
books.InsertOne(session, book);
films.InsertOne(session, film);

// Commits our transaction
session.CommitTransaction();
}
catch (Exception e)
{
Console.WriteLine("Error writing to MongoDB: " + e.Message);
return;
}

// Prints a success message if no error thrown
Console.WriteLine("Successfully committed transaction!");
}
// end-transaction
}

public static void Setup(IMongoDatabase database) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Allman style braces.

database.DropCollection("books");
database.CreateCollection("books");

database.DropCollection("films");
database.CreateCollection("films");
}
}

public class Book
{
public ObjectId Id { get; set; }

[BsonElement("title")]
public string Title { get; set; }

[BsonElement("author")]
public string Author { get; set; }

[BsonElement("inStock")]
public bool InStock { get; set; }
}

public class Film
{
public ObjectId Id { get; set; }

[BsonElement("title")]
public string Title { get; set; }

[BsonElement("director")]
public string Director { get; set; }

[BsonElement("inStock")]
public bool InStock { get; set; }
}
Loading