DATAMONGO-1920 - Polishing.

Slightly tweak method names. Document MongoDatabaseUtils usage in the context of MongoTransactionManager. Rename SessionSynchronization constants to align with AbstractPlatformTransactionManager. Slightly tweak Javadoc and reference docs for typos.

Original pull request: #554.
This commit is contained in:
Mark Paluch
2018-05-04 12:21:15 +02:00
parent 4cd2935087
commit 0d823df7f3
10 changed files with 125 additions and 95 deletions

View File

@@ -1,15 +1,17 @@
[[mongo.sessions]]
= MongoDB Sessions
As of version 3.6 MongoDB supports a concept of Sessions. The use of sessions enables MongoDBs https://docs.mongodb.com/manual/core/read-isolation-consistency-recency/#causal-consistency[Causal Consistency] model guaranteeing to execute operations in an order that respect their causal relationships. Those are split into ``ServerSession``s and ``ClientSession``s. In the following when we speak of session we refer to `ClientSession`.
As of version 3.6, MongoDB supports a concept of Sessions. The use of sessions enables MongoDB's https://docs.mongodb.com/manual/core/read-isolation-consistency-recency/#causal-consistency[Causal Consistency] model guaranteeing to execute operations in an order that respect their causal relationships. Those are split into ``ServerSession``s and ``ClientSession``s. In the following when we speak of session, we refer to `ClientSession`.
WARNING: Operations within a client session are not isolated from operations outside the session.
Both `MongoOperations` and `ReactiveMongoOperations` provide gateway methods for tying a `ClientSession` to the operations themselves. `MongoCollection` and `MongoDatabase` use session proxy objects implementing MongoDB's collection and and database interfaces so there's no need to add a session on each call. This means that a potential call to `MongoCollection#find()` is delegated to `MongoCollection#find(ClientSession)`.
Both `MongoOperations` and `ReactiveMongoOperations` provide gateway methods for tying a `ClientSession` to the operations themselves. `MongoCollection` and `MongoDatabase` use session proxy objects implementing MongoDB's collection and database interfaces, so there's no need to add a session on each call. This means that a potential call to `MongoCollection#find()` is delegated to `MongoCollection#find(ClientSession)`.
NOTE: Methods like `(Reactive)MongoOperations#getCollection` returning native MongoDB Java Driver gateway objects, such as `MongoCollection`, that themselves offer dedicated methods for `ClientSession` are *NOT* be session-proxied. So make sure to provide the `ClientSession` where needed when interacting directly with a `MongoCollection` or `MongoDatabase` and not via one of the `#execute` callbacks on `MongoOperations`.
.ClientSession with `MongoOperations`
Let's take a look at a simple session example:
.`ClientSession` with `MongoOperations`
====
[source,java]
----
@@ -42,7 +44,7 @@ session.close() <4>
WARNING: When dealing with ``DBRef``s, especially lazily loaded ones, it is essential to **not** close the `ClientSession` before all data is loaded. Otherwise, lazy fetch fails.
The reactive counterpart uses the very same building blocks as the imperative one.
The reactive counterpart uses the very same building blocks as the imperative one:
.ClientSession with `ReactiveMongoOperations`
====
@@ -74,19 +76,20 @@ template.withSession(session)
<3> Make sure to close the `ClientSession`.
====
By using a `Publisher` providing the actual session you can defer session acquisition to the point of actual subscription.
Still you need to close the session when done in order to not pollute the server with stale sessions. Use the `doFinally` hook on `execute` to call `ClientSession#close()` when you don't need the session any more.
By using a `Publisher` providing the actual session, you can defer session acquisition to the point of actual subscription.
Still, you need to close the session when done to not pollute the server with stale sessions. Use the `doFinally` hook on `execute` to call `ClientSession#close()` when you don't need the session anymore.
In case you prefer having more control over the session itself, you can always obtain the `ClientSession` via the driver and provide it via a `Supplier`.
[[mongo.transactions]]
= MongoDB Transactions
As of version 4 MongoDB supports https://www.mongodb.com/transactions[Transactions]. Transactions are built on top of <<mongo.sessions,Sessions>> and therefore require an active `ClientSession`.
As of version 4, MongoDB supports https://www.mongodb.com/transactions[Transactions]. Transactions are built on top of <<mongo.sessions,Sessions>> and therefore require an active `ClientSession`.
NOTE: By default, unless you specify a `MongoTransactionManager` within your application context, transaction support is **DISABLED**. You may use `setSessionSynchronization(ANY)` to participate in ongoing non native MongoDB transactions.
NOTE: Unless you specify a `MongoTransactionManager` within your application context, transaction support is **DISABLED**. You may use `setSessionSynchronization(ALWAYS)` to participate in ongoing non-native MongoDB transactions.
To get full programmatic control over transactions you may want to use the session callback on `MongoOperations`.
To get full programmatic control over transactions, you may want to use the session callback on `MongoOperations`.
An example of programmatic transaction control within a `SessionCallback` is shown below:
.Programmatic transactions
====
@@ -123,16 +126,16 @@ template.withSession(session)
<5> Do not forget to close the session when done.
====
The above example allows you to have full control over transactional behavior while using the session scoped `MongoOperations` instance within the callback to ensure the session is passed on to each and every server call.
The above example allows you to have full control over transactional behavior while using the session scoped `MongoOperations` instance within the callback to ensure the session is passed on to every server call.
To avoid some of the overhead that comes with this approach usage of a `TransactionTemplate` can take away some of the noise of manual transaction flow.
== Transactions with TransactionTemplate
== Transactions with `TransactionTemplate`
.Transactions with TransactionTemplate
.Transactions with `TransactionTemplate`
====
[source,java]
----
template.setSessionSynchronization(ANY); <1>
template.setSessionSynchronization(ALWAYS); <1>
// ...
@@ -152,17 +155,17 @@ txTemplate.execute(new TransactionCallbackWithoutResult() {
};
});
----
<1> Manually enable transaction synchronization.
<1> Enable transaction synchronization during Template API configuration. Changing state of `MongoTemplate` during runtime can cause threading/visibility issues.
<2> Create the `TransactionTemplate` using the provided `PlatformTransactionManager`.
<3> Within the callback the `ClientSession` and transaction are already registered.
====
== Transactions with MongoTransactionManager
== Transactions with `MongoTransactionManager`
`MongoTransactionManager` is the gateway to the well known Spring transaction support. It allows applications to use http://docs.spring.io/spring/docs/{springVersion}/spring-framework-reference/html/transaction.html[managed transaction features of Spring].
The `MongoTransactionManager` binds a `ClientSession` to the thread. `MongoTemplate` automatically detects those and operates on them accordingly. `MongoTemplate` can also participate in other, ongoing transactions.
The `MongoTransactionManager` binds a `ClientSession` to the thread. `MongoTemplate` detects those and operates on these resources which are associated with the transaction accordingly. `MongoTemplate` can also participate in other, ongoing transactions.
.Transactions with MongoTransactionManager
.Transactions with `MongoTransactionManager`
====
[source,java]
----
@@ -196,5 +199,5 @@ public class StateService {
<2> Mark methods as transactional.
====
NOTE: `@Transactional(readOnly = true)` advises the `MongoTransactionManager` to also start a transaction adding the
`ClientSession` to outgoing requests.
NOTE: `@Transactional(readOnly = true)` advises `MongoTransactionManager` also to start a transaction adding the
`ClientSession` to outgoing requests.