HHH-17984 initial support for Statistics with StatelessSession
Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
parent
34fd71c131
commit
62132594eb
|
@ -114,6 +114,7 @@ import jakarta.persistence.Tuple;
|
|||
import jakarta.persistence.criteria.CriteriaDelete;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.CriteriaUpdate;
|
||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||
|
||||
import static java.lang.Boolean.TRUE;
|
||||
import static org.hibernate.internal.util.ReflectHelper.isClass;
|
||||
|
@ -311,6 +312,42 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
|
|||
: sessionJdbcBatchSize;
|
||||
}
|
||||
|
||||
void afterTransactionBeginEvents() {
|
||||
getInterceptor().afterTransactionBegin( getTransactionIfAccessible() );
|
||||
}
|
||||
|
||||
void beforeTransactionCompletionEvents() {
|
||||
try {
|
||||
getInterceptor().beforeTransactionCompletion( getTransactionIfAccessible() );
|
||||
}
|
||||
catch (Throwable t) {
|
||||
log.exceptionInBeforeTransactionCompletionInterceptor( t );
|
||||
}
|
||||
}
|
||||
|
||||
void afterTransactionCompletionEvents(boolean successful) {
|
||||
getEventListenerManager().transactionCompletion(successful);
|
||||
|
||||
final StatisticsImplementor statistics = getFactory().getStatistics();
|
||||
if ( statistics.isStatisticsEnabled() ) {
|
||||
statistics.endTransaction(successful);
|
||||
}
|
||||
|
||||
try {
|
||||
getInterceptor().afterTransactionCompletion( getTransactionIfAccessible() );
|
||||
}
|
||||
catch (Throwable t) {
|
||||
log.exceptionInAfterTransactionCompletionInterceptor( t );
|
||||
}
|
||||
}
|
||||
|
||||
private Transaction getTransactionIfAccessible() {
|
||||
// We do not want an exception to be thrown if the transaction
|
||||
// is not accessible. If the transaction is not accessible,
|
||||
// then return null.
|
||||
return fastSessionServices.isJtaTransactionAccessible ? accessTransaction() : null;
|
||||
}
|
||||
|
||||
protected void addSharedSessionTransactionObserver(TransactionCoordinator transactionCoordinator) {
|
||||
}
|
||||
|
||||
|
|
|
@ -1971,24 +1971,12 @@ public class SessionImpl
|
|||
|
||||
private transient LobHelperImpl lobHelper;
|
||||
|
||||
private Transaction getTransactionIfAccessible() {
|
||||
// We do not want an exception to be thrown if the transaction
|
||||
// is not accessible. If the transaction is not accessible,
|
||||
// then return null.
|
||||
return fastSessionServices.isJtaTransactionAccessible ? accessTransaction() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTransactionCompletion() {
|
||||
log.trace( "SessionImpl#beforeTransactionCompletion()" );
|
||||
flushBeforeTransactionCompletion();
|
||||
actionQueue.beforeTransactionCompletion();
|
||||
try {
|
||||
getInterceptor().beforeTransactionCompletion( getTransactionIfAccessible() );
|
||||
}
|
||||
catch (Throwable t) {
|
||||
log.exceptionInBeforeTransactionCompletionInterceptor( t );
|
||||
}
|
||||
beforeTransactionCompletionEvents();
|
||||
super.beforeTransactionCompletion();
|
||||
}
|
||||
|
||||
|
@ -2007,19 +1995,7 @@ public class SessionImpl
|
|||
persistenceContext.afterTransactionCompletion();
|
||||
actionQueue.afterTransactionCompletion( successful );
|
||||
|
||||
getEventListenerManager().transactionCompletion( successful );
|
||||
|
||||
final StatisticsImplementor statistics = getFactory().getStatistics();
|
||||
if ( statistics.isStatisticsEnabled() ) {
|
||||
statistics.endTransaction( successful );
|
||||
}
|
||||
|
||||
try {
|
||||
getInterceptor().afterTransactionCompletion( getTransactionIfAccessible() );
|
||||
}
|
||||
catch (Throwable t) {
|
||||
log.exceptionInAfterTransactionCompletionInterceptor( t );
|
||||
}
|
||||
afterTransactionCompletionEvents( successful );
|
||||
|
||||
if ( !delayed ) {
|
||||
if ( shouldAutoClose() && (!isClosed() || waitingForAutoClose) ) {
|
||||
|
@ -2271,12 +2247,7 @@ public class SessionImpl
|
|||
managedFlush();
|
||||
}
|
||||
actionQueue.beforeTransactionCompletion();
|
||||
try {
|
||||
getInterceptor().beforeTransactionCompletion( getTransactionIfAccessible() );
|
||||
}
|
||||
catch ( Throwable t ) {
|
||||
log.exceptionInBeforeTransactionCompletionInterceptor( t );
|
||||
}
|
||||
beforeTransactionCompletionEvents();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2317,7 +2288,7 @@ public class SessionImpl
|
|||
@Override
|
||||
public void afterTransactionBegin() {
|
||||
checkOpenOrWaitingForAutoClose();
|
||||
getInterceptor().afterTransactionBegin( getTransactionIfAccessible() );
|
||||
afterTransactionBeginEvents();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -59,6 +59,7 @@ import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
|||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.proxy.LazyInitializer;
|
||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||
import org.hibernate.tuple.entity.EntityMetamodel;
|
||||
|
||||
import jakarta.persistence.EntityGraph;
|
||||
|
@ -152,6 +153,10 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
|
|||
forEachOwnedCollection( entity, id, persister,
|
||||
(descriptor, collection) -> descriptor.recreate( collection, id, this) );
|
||||
firePostInsert(entity, id, state, persister);
|
||||
final StatisticsImplementor statistics = getFactory().getStatistics();
|
||||
if ( statistics.isStatisticsEnabled() ) {
|
||||
statistics.insertEntity( persister.getEntityName() );
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
|
@ -176,6 +181,10 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
|
|||
(descriptor, collection) -> descriptor.remove(id, this) );
|
||||
persister.getDeleteCoordinator().delete( entity, id, version, this );
|
||||
firePostDelete(entity, id, persister);
|
||||
final StatisticsImplementor statistics = getFactory().getStatistics();
|
||||
if ( statistics.isStatisticsEnabled() ) {
|
||||
statistics.deleteEntity( persister.getEntityName() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -220,6 +229,10 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
|
|||
forEachOwnedCollection( entity, id, persister,
|
||||
(descriptor, collection) -> descriptor.recreate( collection, id, this) );
|
||||
firePostUpdate(entity, id, state, persister);
|
||||
final StatisticsImplementor statistics = getFactory().getStatistics();
|
||||
if ( statistics.isStatisticsEnabled() ) {
|
||||
statistics.updateEntity( persister.getEntityName() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -234,7 +247,6 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
|
|||
.onUpsert( entity, id, state, persister.getPropertyNames(), persister.getPropertyTypes() );
|
||||
final Object oldVersion = versionToUpsert( entity, persister, state );
|
||||
persister.getMergeCoordinator().update( entity, id, null, state, oldVersion, null, null, false, this );
|
||||
// TODO: need PreUpsert and PostUpsert events!
|
||||
// TODO: can we do better here?
|
||||
forEachOwnedCollection( entity, id, persister,
|
||||
(descriptor, collection) -> descriptor.remove(id, this) );
|
||||
|
@ -884,15 +896,18 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
|
|||
|
||||
@Override
|
||||
public void afterTransactionBegin() {
|
||||
afterTransactionBeginEvents();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTransactionCompletion() {
|
||||
flushBeforeTransactionCompletion();
|
||||
beforeTransactionCompletionEvents();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTransactionCompletion(boolean successful, boolean delayed) {
|
||||
afterTransactionCompletionEvents( successful );
|
||||
if ( shouldAutoClose() && !isClosed() ) {
|
||||
managedClose();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
package org.hibernate.orm.test.stateless;
|
||||
|
||||
import jakarta.persistence.Basic;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hibernate.cfg.StatisticsSettings.GENERATE_STATISTICS;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
@SessionFactory
|
||||
@DomainModel(annotatedClasses = StatelessSessionStatisticsTest.Person.class)
|
||||
@ServiceRegistry(settings = @Setting(name = GENERATE_STATISTICS, value = "true"))
|
||||
public class StatelessSessionStatisticsTest {
|
||||
@Test
|
||||
void test(SessionFactoryScope scope) {
|
||||
StatisticsImplementor statistics = scope.getSessionFactory().getStatistics();
|
||||
assertEquals(0, statistics.getEntityInsertCount());
|
||||
assertEquals(0, statistics.getEntityUpdateCount());
|
||||
assertEquals(0, statistics.getEntityDeleteCount());
|
||||
assertEquals(0, statistics.getEntityLoadCount());
|
||||
Person person = new Person();
|
||||
person.name = "Gavin";
|
||||
scope.inStatelessTransaction(s -> s.insert(person));
|
||||
assertEquals(1, statistics.getEntityInsertCount());
|
||||
scope.inStatelessSession(s -> s.get(Person.class, person.id));
|
||||
assertEquals(1, statistics.getEntityLoadCount());
|
||||
person.name = "Gavin King";
|
||||
scope.inStatelessTransaction(s -> s.update(person));
|
||||
assertEquals(1, statistics.getEntityUpdateCount());
|
||||
scope.inStatelessSession(s -> s.get(Person.class, person.id));
|
||||
assertEquals(2, statistics.getEntityLoadCount());
|
||||
scope.inStatelessTransaction(s -> s.delete(person));
|
||||
assertEquals(1, statistics.getEntityDeleteCount());
|
||||
assertEquals(3, statistics.getTransactionCount());
|
||||
}
|
||||
|
||||
@Entity(name="Entity")
|
||||
static class Person {
|
||||
@Id @GeneratedValue
|
||||
long id;
|
||||
@Basic(optional = false)
|
||||
String name;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue