Skip to content

Commit

Permalink
Allow accessing the MongoDB ClientSession programmatively
Browse files Browse the repository at this point in the history
  • Loading branch information
loicmathieu committed Apr 24, 2023
1 parent a26e071 commit 39cc4fc
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 2 deletions.
2 changes: 2 additions & 0 deletions docs/src/main/asciidoc/mongodb-panache.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,8 @@ MongoDB offers ACID transactions since version 4.0.

To use them with MongoDB with Panache you need to annotate the method that starts the transaction with the `@Transactional` annotation.

Inside methods annotated with `@Transactional` you can access the `ClientSession` with `Panache.getClientSession()` if needed.

In MongoDB, a transaction is only possible on a replicaset,
luckily our xref:mongodb.adoc#dev-services[Dev Services for MongoDB] setups a single node replicaset so it is compatible with transactions.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -333,23 +333,27 @@ ClientSession getSession(Object entity) {
return getSession(entity.getClass());
}

ClientSession getSession(Class<?> entityClass) {
public ClientSession getSession(Class<?> entityClass) {
ClientSession clientSession = null;
MongoEntity mongoEntity = entityClass.getAnnotation(MongoEntity.class);
InstanceHandle<TransactionSynchronizationRegistry> instance = Arc.container()
.instance(TransactionSynchronizationRegistry.class);
if (instance.isAvailable()) {
TransactionSynchronizationRegistry registry = instance.get();
if (registry.getTransactionStatus() == Status.STATUS_ACTIVE) {
clientSession = (ClientSession) registry.getResource(SESSION_KEY);
if (clientSession == null) {
MongoEntity mongoEntity = entityClass == null ? null : entityClass.getAnnotation(MongoEntity.class);
return registerClientSession(mongoEntity, registry);
}
}
}
return clientSession;
}

public ClientSession getSession() {
return getSession(null);
}

private ClientSession registerClientSession(MongoEntity mongoEntity,
TransactionSynchronizationRegistry registry) {
TransactionManager transactionManager = Arc.container().instance(TransactionManager.class).get();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.quarkus.mongodb.panache.kotlin

import com.mongodb.session.ClientSession
import io.quarkus.mongodb.panache.kotlin.runtime.KotlinMongoOperations

object Panache {
/**
* Access the current MongoDB ClientSession from the transaction context. Can be used inside a
* method annotated with `@Transactional` to manually access the client session.
*
* @return ClientSession or null if not in the context of a transaction.
*/
val session: ClientSession
get() = KotlinMongoOperations.INSTANCE.session

/**
* Access the current MongoDB ClientSession from the transaction context.
*
* @param entityClass the class of the MongoDB entity in case it is configured to use the
* non-default client.
* @return ClientSession or null if not in the context of a transaction.
* @see [session]
*/
fun getSession(entityClass: Class<*>?): ClientSession {
return KotlinMongoOperations.INSTANCE.getSession(entityClass)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package io.quarkus.mongodb.panache;

import com.mongodb.session.ClientSession;

import io.quarkus.mongodb.panache.runtime.JavaMongoOperations;

public class Panache {

/**
* Access the current MongoDB ClientSession from the transaction context.
* Can be used inside a method annotated with `@Transactional` to manually access the client session.
*
* @return ClientSession or null if not in the context of a transaction.
*/
public static ClientSession getSession() {
return JavaMongoOperations.INSTANCE.getSession();
}

/**
* Access the current MongoDB ClientSession from the transaction context.
*
* @see #getSession()
*
* @param entityClass the class of the MongoDB entity in case it is configured to use the non-default client.
* @return ClientSession or null if not in the context of a transaction.
*/
public static ClientSession getSession(Class<?> entityClass) {
return JavaMongoOperations.INSTANCE.getSession(entityClass);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.util.ArrayList;
import java.util.List;

import io.quarkus.mongodb.panache.Panache;
import jakarta.enterprise.event.Observes;
import jakarta.inject.Inject;
import jakarta.inject.Named;
Expand All @@ -16,6 +17,8 @@

import io.quarkus.runtime.StartupEvent;

import static org.junit.jupiter.api.Assertions.assertNotNull;

@Path("/transaction")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
Expand All @@ -42,6 +45,7 @@ public List<TransactionPerson> getPersons() {
@Transactional
public Response addPerson(TransactionPerson person) {
person.persist();
assertNotNull(Panache.getSession(TransactionPerson.class));
return Response.created(URI.create("/transaction/" + person.id.toString())).build();
}

Expand Down

0 comments on commit 39cc4fc

Please sign in to comment.