DATAMONGO-1880 - Add support for ClientSession.
We now support ClientSession via MongoOperations and ReactiveMongoOperations. Client sessions introduce causal consistency and retryable writes. A client Session can be either provided by application code or managed by specifying ClientSessionOptions. Binding a ClientSession via MongoOperations.withSession(…) provides access to a Session-bound MongoOperations instance that associates the session with each MongoDB operation.
ClientSession support applies only to MongoOperations and ReactiveMongoOperations and is not yet available via repositories.
ClientSession session = client.startSession(ClientSessionOptions.builder().causallyConsistent(true).build());
Person person = template.withSession(() -> session)
.execute(action -> {
action.insert(new Person("wohoo"));
return action.findOne(query(where("id").is("wohoo")), Person.class);
});
session.close();
Original pull request: #536.
This commit is contained in:
committed by
Mark Paluch
parent
caab310cf8
commit
b9f7f23b8f
@@ -27,6 +27,7 @@ include::{spring-data-commons-docs}/repositories.adoc[]
|
||||
include::reference/introduction.adoc[]
|
||||
include::reference/mongodb.adoc[]
|
||||
include::reference/reactive-mongodb.adoc[]
|
||||
include::reference/client-session.adoc[]
|
||||
include::reference/mongo-repositories.adoc[]
|
||||
include::reference/reactive-mongo-repositories.adoc[]
|
||||
include::{spring-data-commons-docs}/auditing.adoc[]
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
* <<mongo.jsonSchema,`$jsonSchema` support>> for queries and collection creation.
|
||||
* <<change-streams, Change Stream support>> for imperative and reactive drivers.
|
||||
* Tailable cursors for imperative driver.
|
||||
* <<mongo.sessions, MongoDB Session>> support for the imperative and reactive Template API.
|
||||
|
||||
[[new-features.2-0-0]]
|
||||
== What's new in Spring Data MongoDB 2.0
|
||||
|
||||
79
src/main/asciidoc/reference/client-session.adoc
Normal file
79
src/main/asciidoc/reference/client-session.adoc
Normal file
@@ -0,0 +1,79 @@
|
||||
[[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`.
|
||||
|
||||
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. Within the callback all operations on `MongoCollection` and `MongoDatabase` are called with the provided session via a `Proxy` without the need to add it manually. 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` will *NOT* be wrapped by the `Proxy`. So please make sure to provide the `ClientSession` where needed when interacting directly with a `MongoCollection` or `MongoDatabase` and not via one of the `#excute` callbacks on `MongoOperations`.
|
||||
|
||||
.ClientSession with MongoOperations.
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
ClientSessionOptions sessionOptions = ClientSessionOptions.builder()
|
||||
.causallyConsistent(true)
|
||||
.build();
|
||||
|
||||
ClientSession session = client.startSession(sessionOptions); <1>
|
||||
|
||||
template.withSession(() -> session)
|
||||
.execute(action -> {
|
||||
|
||||
Query query = query(where("name").is("Durzo Blint"));
|
||||
Person durzo = action.findOne(query, Person.class); <2>
|
||||
|
||||
Person azoth = new Person("Kylar Stern");
|
||||
azoth.setMaster(durzo);
|
||||
|
||||
action.insert(azoth); <2>
|
||||
|
||||
return azoth;
|
||||
});
|
||||
|
||||
session.close() <4>
|
||||
----
|
||||
<1> Obtain a new session from the server.
|
||||
<2> Use `MongoOperation` methods as before. The `ClientSession` gets applied automatically.
|
||||
<3> Important! Do not forget to close the session.
|
||||
====
|
||||
|
||||
WARNING: When dealing with ``DBRef``s, especially lazily loaded ones, it is essential to **not** close the `ClientSession` before all data is loaded.
|
||||
|
||||
The reactive counterpart uses the very same building blocks as the imperative one.
|
||||
|
||||
.ClientSession with ReactiveMongoOperations.
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
ClientSessionOptions sessionOptions = ClientSessionOptions.builder()
|
||||
.causallyConsistent(true)
|
||||
.build();
|
||||
|
||||
Publisher<ClientSession> session = client.startSession(sessionOptions); <1>
|
||||
|
||||
template.withSession(session)
|
||||
.execute(action -> {
|
||||
|
||||
Query query = query(where("name").is("Durzo Blint"));
|
||||
return action.findOne(query, Person.class)
|
||||
.flatMap(durzo -> {
|
||||
|
||||
Person azoth = new Person("Kylar Stern");
|
||||
azoth.setMaster(durzo);
|
||||
|
||||
return action.insert(azoth); <2>
|
||||
});
|
||||
}, ClientSession::close) <4>
|
||||
.subscribe();
|
||||
----
|
||||
<1> Obtain a `Publisher` for new session retrieval.
|
||||
<2> Use `MongoOperation` methods as before. The `ClientSession` is obtained and applied automatically.
|
||||
<3> Important! Do not forget to close the session.
|
||||
====
|
||||
|
||||
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.
|
||||
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`.
|
||||
Reference in New Issue
Block a user