Skip to content

Commit

Permalink
Support fror @Inject StatelessSession
Browse files Browse the repository at this point in the history
Why:

 * Sometimes you just want to do raw data access

This change addreses the need by:

 * Add StatelessSession as a possible injection.

Signed-off-by: Max Rydahl Andersen <manderse@redhat.com>
  • Loading branch information
maxandersen committed May 15, 2020
1 parent 49de311 commit 3c9a46b
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 1 deletion.
30 changes: 30 additions & 0 deletions docs/src/main/asciidoc/hibernate-orm.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,36 @@ WARNING: Make sure to wrap methods modifying your database (e.g. `entity.persist
CDI bean method `@Transactional` will do that for you and make that method a transaction boundary. We recommend doing
so at your application entry point boundaries like your REST endpoint controllers.

=== Processing raw or large amount of data

`StatelessSession` are supported too and can be injected and used standalone or inter-mixed with your `EntityManager`.
The benefits of `StatelessSession` are that entities are not put in a session-level cache, allowing for more raw and in some cases higher performance
data access. Especially useful when reading/processing large amount of data.

[source,java]
.Example application bean using Hibernate
--
@ApplicationScoped
public class SantaClausService {
@Inject
StatelessSession session; <.>

@Transactional
public void queryGifts(String giftDescription) {
ScrollableResults gifts = session.getQuery("from Gift")
.scroll(ScrollMode.FORWARD_ONLY); <.>
while ( gifts.next() ) {
Gift gift = (Gift) gifts.get(0);
gift.updateStuff(...);
session.update(customer); <.>
}
}
}
--
<.> Inject your stateless session and have fun; it will open or reuse the active transaction.
<.> Using `scroll()` means you can process the data without loading the complete resultset or list of data in memory.
<.> Since using a stateless session you need to explicitly call `update()` to save changes.

[[hibernate-configuration-properties]]
=== Hibernate ORM configuration properties

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
import io.quarkus.hibernate.orm.deployment.integration.HibernateOrmIntegrationRuntimeConfiguredBuildItem;
import io.quarkus.hibernate.orm.runtime.DefaultEntityManagerFactoryProducer;
import io.quarkus.hibernate.orm.runtime.DefaultEntityManagerProducer;
import io.quarkus.hibernate.orm.runtime.DefaultStatelessSessionProducer;
import io.quarkus.hibernate.orm.runtime.HibernateOrmRecorder;
import io.quarkus.hibernate.orm.runtime.JPAConfig;
import io.quarkus.hibernate.orm.runtime.JPAResourceReferenceProvider;
Expand Down Expand Up @@ -421,6 +422,7 @@ void registerBeans(BuildProducer<AdditionalBeanBuildItem> additionalBeans, Combi
if (isUserDefinedProducerMissing(combinedIndex.getIndex(), PERSISTENCE_CONTEXT)) {
additionalBeans.produce(new AdditionalBeanBuildItem(DefaultEntityManagerProducer.class));
}
additionalBeans.produce(new AdditionalBeanBuildItem(DefaultStatelessSessionProducer.class));
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package io.quarkus.hibernate.orm;

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

import java.util.List;

import javax.inject.Inject;

import org.hibernate.StatelessSession;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.arc.Arc;
import io.quarkus.hibernate.orm.enhancer.Address;
import io.quarkus.test.QuarkusUnitTest;

/**
* @author Max Rydahl Andersen <manderse@redhat.com>
*/
public class StatelessSessionTest {

@RegisterExtension
static QuarkusUnitTest runner = new QuarkusUnitTest()
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
.addClass(Address.class)
.addAsResource("application.properties"));

@Inject
StatelessSession statelessSession;

@Test
public void testStatelessSession() {
Arc.container().requestContext().activate();
try {
List list = statelessSession.createNativeQuery("SELECT VALUE FROM INFORMATION_SCHEMA.SETTINGS")
.addScalar("VALUE")
.list();
assertNotNull(list);
} finally {
Arc.container().requestContext().terminate();
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.quarkus.hibernate.orm.runtime;

import javax.enterprise.inject.Produces;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.persistence.EntityManagerFactory;

import org.hibernate.SessionFactory;
import org.hibernate.StatelessSession;

public class DefaultStatelessSessionProducer {

@Inject
EntityManagerFactory em;

@Produces
@Singleton
StatelessSession produceStatelessSession() {
return em.unwrap(SessionFactory.class).openStatelessSession();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceUnit;

import org.hibernate.StatelessSession;

import io.quarkus.arc.Arc;
import io.quarkus.arc.InstanceHandle;
import io.quarkus.arc.ResourceReferenceProvider;
Expand Down Expand Up @@ -56,8 +58,39 @@ public void destroy() {
};
}
}
}
} else if (StatelessSession.class.equals(type)) {
PersistenceContext pc = getAnnotation(annotations, PersistenceContext.class);
if (pc != null) {
if (jpaConfig.isJtaEnabled()) {
TransactionEntityManagers transactionEntityManagers = Arc.container()
.instance(TransactionEntityManagers.class).get();
ForwardingEntityManager entityManager = new ForwardingEntityManager() {

@Override
protected EntityManager delegate() {
return transactionEntityManagers.getEntityManager(pc.unitName());
}
};
return () -> entityManager;
} else {
EntityManagerFactory entityManagerFactory = jpaConfig.getEntityManagerFactory(pc.unitName());
EntityManager entityManager = entityManagerFactory.createEntityManager();
return new InstanceHandle<Object>() {

@Override
public Object get() {
return entityManager;
}

@Override
public void destroy() {
entityManager.close();
}
};
}
}

}
return null;
}

Expand Down

0 comments on commit 3c9a46b

Please sign in to comment.