HHH-17989 - Fix for StatisticsImplementor.closeStatement() never called

Signed-off-by: Jan Schatteman <jschatte@redhat.com>
This commit is contained in:
Jan Schatteman 2024-10-24 14:33:38 +02:00 committed by Jan Schatteman
parent ddf936286f
commit cb0d70309a
5 changed files with 47 additions and 4 deletions

View File

@ -47,6 +47,7 @@ import org.hibernate.mapping.Column;
import org.hibernate.mapping.PrimaryKey; import org.hibernate.mapping.PrimaryKey;
import org.hibernate.mapping.Table; import org.hibernate.mapping.Table;
import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistry;
import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.type.BasicTypeRegistry; import org.hibernate.type.BasicTypeRegistry;
import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.Type; import org.hibernate.type.Type;
@ -624,13 +625,20 @@ public class TableGenerator implements PersistentIdentifierGenerator {
logger.logStatement( sql, FormatStyle.BASIC.getFormatter() ); logger.logStatement( sql, FormatStyle.BASIC.getFormatter() );
final EventManager eventManager = session.getEventManager(); final EventManager eventManager = session.getEventManager();
final HibernateMonitoringEvent creationEvent = eventManager.beginJdbcPreparedStatementCreationEvent(); final HibernateMonitoringEvent creationEvent = eventManager.beginJdbcPreparedStatementCreationEvent();
final StatisticsImplementor stats = session.getFactory().getStatistics();
try { try {
listener.jdbcPrepareStatementStart(); listener.jdbcPrepareStatementStart();
if ( stats != null && stats.isStatisticsEnabled() ) {
stats.prepareStatement();
}
return connection.prepareStatement( sql ); return connection.prepareStatement( sql );
} }
finally { finally {
eventManager.completeJdbcPreparedStatementCreationEvent( creationEvent, sql ); eventManager.completeJdbcPreparedStatementCreationEvent( creationEvent, sql );
listener.jdbcPrepareStatementEnd(); listener.jdbcPrepareStatementEnd();
if ( stats != null && stats.isStatisticsEnabled() ) {
stats.closeStatement();
}
} }
} }

View File

@ -31,6 +31,7 @@ import org.hibernate.id.IntegralDataTypeHolder;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.jdbc.AbstractReturningWork; import org.hibernate.jdbc.AbstractReturningWork;
import org.hibernate.mapping.Table; import org.hibernate.mapping.Table;
import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.StandardBasicTypes;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
@ -231,13 +232,20 @@ public class TableStructure implements DatabaseStructure {
logger.logStatement( sql, FormatStyle.BASIC.getFormatter() ); logger.logStatement( sql, FormatStyle.BASIC.getFormatter() );
final EventManager eventManager = session.getEventManager(); final EventManager eventManager = session.getEventManager();
final HibernateMonitoringEvent creationEvent = eventManager.beginJdbcPreparedStatementCreationEvent(); final HibernateMonitoringEvent creationEvent = eventManager.beginJdbcPreparedStatementCreationEvent();
final StatisticsImplementor stats = session.getFactory().getStatistics();
try { try {
statsCollector.jdbcPrepareStatementStart(); statsCollector.jdbcPrepareStatementStart();
if ( stats != null && stats.isStatisticsEnabled() ) {
stats.prepareStatement();
}
return connection.prepareStatement( sql ); return connection.prepareStatement( sql );
} }
finally { finally {
eventManager.completeJdbcPreparedStatementCreationEvent( creationEvent, sql ); eventManager.completeJdbcPreparedStatementCreationEvent( creationEvent, sql );
statsCollector.jdbcPrepareStatementEnd(); statsCollector.jdbcPrepareStatementEnd();
if ( stats != null && stats.isStatisticsEnabled() ) {
stats.closeStatement();
}
} }
} }

View File

@ -80,6 +80,10 @@ public class JdbcEventHandler {
if ( sessionListener != null ) { if ( sessionListener != null ) {
sessionListener.jdbcPrepareStatementStart(); sessionListener.jdbcPrepareStatementStart();
} }
if ( statistics != null && statistics.isStatisticsEnabled() ) {
statistics.prepareStatement();
}
} }
public void jdbcPrepareStatementEnd() { public void jdbcPrepareStatementEnd() {
@ -88,7 +92,7 @@ public class JdbcEventHandler {
} }
if ( statistics != null && statistics.isStatisticsEnabled() ) { if ( statistics != null && statistics.isStatisticsEnabled() ) {
statistics.prepareStatement(); statistics.closeStatement();
} }
} }

View File

@ -10,6 +10,7 @@ import jakarta.persistence.Entity;
import jakarta.persistence.FetchType; import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue; import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import org.hibernate.dialect.Dialect;
import org.hibernate.stat.spi.StatisticsImplementor; import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.ServiceRegistry; import org.hibernate.testing.orm.junit.ServiceRegistry;
@ -20,6 +21,7 @@ import org.junit.jupiter.api.Test;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale;
import static org.hibernate.cfg.StatisticsSettings.GENERATE_STATISTICS; import static org.hibernate.cfg.StatisticsSettings.GENERATE_STATISTICS;
import static org.hibernate.graph.GraphSemantic.FETCH; import static org.hibernate.graph.GraphSemantic.FETCH;
@ -32,22 +34,31 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
public class StatelessSessionStatisticsTest { public class StatelessSessionStatisticsTest {
@Test @Test
void test(SessionFactoryScope scope) { void test(SessionFactoryScope scope) {
StatisticsImplementor statistics = scope.getSessionFactory().getStatistics(); final StatisticsImplementor statistics = scope.getSessionFactory().getStatistics();
final Dialect dialect = scope.fromSession( session -> session.getDialect() );
final boolean isSybaseOrMysql = dialect.getClass().getName().toLowerCase( Locale.ROOT ).split( "sybase|mysql" ).length == 2;
int stmtCount = isSybaseOrMysql ? 4 : 3;
assertEquals(0, statistics.getEntityInsertCount()); assertEquals(0, statistics.getEntityInsertCount());
assertEquals(0, statistics.getEntityUpdateCount()); assertEquals(0, statistics.getEntityUpdateCount());
assertEquals(0, statistics.getEntityDeleteCount()); assertEquals(0, statistics.getEntityDeleteCount());
assertEquals(0, statistics.getEntityLoadCount()); assertEquals(0, statistics.getEntityLoadCount());
assertEquals(0, statistics.getPrepareStatementCount());
Person person = new Person(); Person person = new Person();
person.name = "Gavin"; person.name = "Gavin";
person.handles.add("@1ovthafew"); person.handles.add("@1ovthafew");
scope.inStatelessTransaction(s -> s.insert(person)); scope.inStatelessTransaction(s -> s.insert(person));
assertEquals(1, statistics.getEntityInsertCount()); assertEquals(1, statistics.getEntityInsertCount());
assertEquals(1, statistics.getCollectionRecreateCount()); assertEquals(1, statistics.getCollectionRecreateCount());
assertEquals(stmtCount, statistics.getPrepareStatementCount());
assertEquals(stmtCount, statistics.getCloseStatementCount());
scope.inStatelessSession(s -> s.get(Person.class, person.id)); scope.inStatelessSession(s -> s.get(Person.class, person.id));
assertEquals(1, statistics.getEntityLoadCount()); assertEquals(1, statistics.getEntityLoadCount());
assertEquals(0, statistics.getEntityFetchCount()); assertEquals(0, statistics.getEntityFetchCount());
assertEquals(1, statistics.getCollectionLoadCount()); assertEquals(1, statistics.getCollectionLoadCount());
assertEquals(0, statistics.getCollectionFetchCount()); assertEquals(0, statistics.getCollectionFetchCount());
assertEquals(++stmtCount, statistics.getPrepareStatementCount());
assertEquals(stmtCount, statistics.getCloseStatementCount());
person.name = "Gavin King"; person.name = "Gavin King";
scope.inStatelessTransaction(s -> s.update(person)); scope.inStatelessTransaction(s -> s.update(person));
assertEquals(1, statistics.getEntityUpdateCount()); assertEquals(1, statistics.getEntityUpdateCount());
@ -56,25 +67,37 @@ public class StatelessSessionStatisticsTest {
assertEquals(2, statistics.getEntityLoadCount()); assertEquals(2, statistics.getEntityLoadCount());
assertEquals(2, statistics.getCollectionLoadCount()); assertEquals(2, statistics.getCollectionLoadCount());
assertEquals(0, statistics.getCollectionFetchCount()); assertEquals(0, statistics.getCollectionFetchCount());
assertEquals(stmtCount+=4, statistics.getPrepareStatementCount());
assertEquals(stmtCount, statistics.getCloseStatementCount());
scope.inStatelessSession(s -> s.get(s.createEntityGraph(Person.class), FETCH, person.id)); scope.inStatelessSession(s -> s.get(s.createEntityGraph(Person.class), FETCH, person.id));
assertEquals(3, statistics.getEntityLoadCount()); assertEquals(3, statistics.getEntityLoadCount());
assertEquals(2, statistics.getCollectionLoadCount()); assertEquals(2, statistics.getCollectionLoadCount());
assertEquals(0, statistics.getCollectionFetchCount()); assertEquals(0, statistics.getCollectionFetchCount());
assertEquals(++stmtCount, statistics.getPrepareStatementCount());
assertEquals(stmtCount, statistics.getCloseStatementCount());
scope.inStatelessSession(s -> s.fetch(s.get(s.createEntityGraph(Person.class), FETCH, person.id).handles)); scope.inStatelessSession(s -> s.fetch(s.get(s.createEntityGraph(Person.class), FETCH, person.id).handles));
assertEquals(4, statistics.getEntityLoadCount()); assertEquals(4, statistics.getEntityLoadCount());
assertEquals(3, statistics.getCollectionLoadCount()); assertEquals(3, statistics.getCollectionLoadCount());
assertEquals(1, statistics.getCollectionFetchCount()); assertEquals(1, statistics.getCollectionFetchCount());
assertEquals(stmtCount+=2, statistics.getPrepareStatementCount());
assertEquals(stmtCount, statistics.getCloseStatementCount());
scope.inStatelessSession(s -> s.createQuery("from Person", Person.class).getSingleResult()); scope.inStatelessSession(s -> s.createQuery("from Person", Person.class).getSingleResult());
assertEquals(5, statistics.getEntityLoadCount()); assertEquals(5, statistics.getEntityLoadCount());
assertEquals(4, statistics.getCollectionLoadCount()); assertEquals(4, statistics.getCollectionLoadCount());
assertEquals(2, statistics.getCollectionFetchCount()); assertEquals(2, statistics.getCollectionFetchCount());
assertEquals(stmtCount+=2, statistics.getPrepareStatementCount());
assertEquals(stmtCount, statistics.getCloseStatementCount());
person.handles.add("hello world"); person.handles.add("hello world");
scope.inStatelessTransaction(s -> s.upsert(person)); scope.inStatelessTransaction(s -> s.upsert(person));
assertEquals(2, statistics.getCollectionUpdateCount()); assertEquals(2, statistics.getCollectionUpdateCount());
assertEquals(stmtCount+=4, statistics.getPrepareStatementCount());
assertEquals(stmtCount, statistics.getCloseStatementCount());
scope.inStatelessTransaction(s -> s.delete(person)); scope.inStatelessTransaction(s -> s.delete(person));
assertEquals(1, statistics.getEntityDeleteCount()); assertEquals(1, statistics.getEntityDeleteCount());
assertEquals(1, statistics.getCollectionRemoveCount()); assertEquals(1, statistics.getCollectionRemoveCount());
assertEquals(4, statistics.getTransactionCount()); assertEquals(4, statistics.getTransactionCount());
assertEquals(stmtCount+=2, statistics.getPrepareStatementCount());
assertEquals(stmtCount, statistics.getCloseStatementCount());
} }
@Entity(name="Person") @Entity(name="Person")

View File

@ -21,11 +21,11 @@ import org.junit.jupiter.api.Test;
@DomainModel @DomainModel
@SessionFactory @SessionFactory
@ServiceRegistry( @ServiceRegistry(
settingProviders = @SettingProvider(provider = StatisticsWithNoCachingTest.RegionFacrotySettingProvider.class, settingName = AvailableSettings.CACHE_REGION_FACTORY) settingProviders = @SettingProvider(provider = StatisticsWithNoCachingTest.RegionFactorySettingProvider.class, settingName = AvailableSettings.CACHE_REGION_FACTORY)
) )
public class StatisticsWithNoCachingTest { public class StatisticsWithNoCachingTest {
public static class RegionFacrotySettingProvider implements SettingProvider.Provider<String> { public static class RegionFactorySettingProvider implements SettingProvider.Provider<String> {
@Override @Override
public String getSetting() { public String getSetting() {