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

Allow accessing the ClientSession programmatively #30115

Merged
merged 1 commit into from
Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from all 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 docs/src/main/asciidoc/mongodb-panache.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -770,6 +770,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
@@ -1,5 +1,7 @@
package io.quarkus.it.mongodb.panache.transaction;

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

import java.net.URI;
import java.util.ArrayList;
import java.util.List;
Expand All @@ -14,6 +16,7 @@

import com.mongodb.client.MongoClient;

import io.quarkus.mongodb.panache.Panache;
import io.quarkus.runtime.StartupEvent;

@Path("/transaction")
Expand Down Expand Up @@ -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
Loading