From edac5cff7919c7297eedbe1b82bdbc17e6522cba Mon Sep 17 00:00:00 2001 From: Jan Schatteman Date: Thu, 24 Oct 2024 14:33:38 +0200 Subject: [PATCH] HHH-17989 - Fix for StatisticsImplementor.closeStatement() never called Signed-off-by: Jan Schatteman --- .../hibernate/id/enhanced/TableGenerator.java | 8 ++++++ .../hibernate/id/enhanced/TableStructure.java | 8 ++++++ .../resource/jdbc/spi/JdbcEventHandler.java | 6 ++++- .../StatelessSessionStatisticsTest.java | 25 ++++++++++++++++++- .../stats/StatisticsWithNoCachingTest.java | 4 +-- 5 files changed, 47 insertions(+), 4 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java index 8d775c5c9666..7a3c396968bf 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java @@ -47,6 +47,7 @@ import org.hibernate.mapping.PrimaryKey; import org.hibernate.mapping.Table; import org.hibernate.service.ServiceRegistry; +import org.hibernate.stat.spi.StatisticsImplementor; import org.hibernate.type.BasicTypeRegistry; import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.Type; @@ -624,13 +625,20 @@ private PreparedStatement prepareStatement( logger.logStatement( sql, FormatStyle.BASIC.getFormatter() ); final EventManager eventManager = session.getEventManager(); final HibernateMonitoringEvent creationEvent = eventManager.beginJdbcPreparedStatementCreationEvent(); + final StatisticsImplementor stats = session.getFactory().getStatistics(); try { listener.jdbcPrepareStatementStart(); + if ( stats != null && stats.isStatisticsEnabled() ) { + stats.prepareStatement(); + } return connection.prepareStatement( sql ); } finally { eventManager.completeJdbcPreparedStatementCreationEvent( creationEvent, sql ); listener.jdbcPrepareStatementEnd(); + if ( stats != null && stats.isStatisticsEnabled() ) { + stats.closeStatement(); + } } } diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableStructure.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableStructure.java index df3bdf824c86..5fde5a4b8845 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableStructure.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableStructure.java @@ -31,6 +31,7 @@ import org.hibernate.internal.CoreMessageLogger; import org.hibernate.jdbc.AbstractReturningWork; import org.hibernate.mapping.Table; +import org.hibernate.stat.spi.StatisticsImplementor; import org.hibernate.type.StandardBasicTypes; import org.jboss.logging.Logger; @@ -231,13 +232,20 @@ private PreparedStatement prepareStatement( logger.logStatement( sql, FormatStyle.BASIC.getFormatter() ); final EventManager eventManager = session.getEventManager(); final HibernateMonitoringEvent creationEvent = eventManager.beginJdbcPreparedStatementCreationEvent(); + final StatisticsImplementor stats = session.getFactory().getStatistics(); try { statsCollector.jdbcPrepareStatementStart(); + if ( stats != null && stats.isStatisticsEnabled() ) { + stats.prepareStatement(); + } return connection.prepareStatement( sql ); } finally { eventManager.completeJdbcPreparedStatementCreationEvent( creationEvent, sql ); statsCollector.jdbcPrepareStatementEnd(); + if ( stats != null && stats.isStatisticsEnabled() ) { + stats.closeStatement(); + } } } diff --git a/hibernate-core/src/main/java/org/hibernate/resource/jdbc/spi/JdbcEventHandler.java b/hibernate-core/src/main/java/org/hibernate/resource/jdbc/spi/JdbcEventHandler.java index a8317b70463f..52ff415859f3 100644 --- a/hibernate-core/src/main/java/org/hibernate/resource/jdbc/spi/JdbcEventHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/resource/jdbc/spi/JdbcEventHandler.java @@ -80,6 +80,10 @@ public void jdbcPrepareStatementStart() { if ( sessionListener != null ) { sessionListener.jdbcPrepareStatementStart(); } + + if ( statistics != null && statistics.isStatisticsEnabled() ) { + statistics.prepareStatement(); + } } public void jdbcPrepareStatementEnd() { @@ -88,7 +92,7 @@ public void jdbcPrepareStatementEnd() { } if ( statistics != null && statistics.isStatisticsEnabled() ) { - statistics.prepareStatement(); + statistics.closeStatement(); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/StatelessSessionStatisticsTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/StatelessSessionStatisticsTest.java index 4480fe7891a9..b5d915fd4f3a 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/StatelessSessionStatisticsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/StatelessSessionStatisticsTest.java @@ -10,6 +10,7 @@ import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; +import org.hibernate.dialect.Dialect; import org.hibernate.stat.spi.StatisticsImplementor; import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.ServiceRegistry; @@ -20,6 +21,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Locale; import static org.hibernate.cfg.StatisticsSettings.GENERATE_STATISTICS; import static org.hibernate.graph.GraphSemantic.FETCH; @@ -32,22 +34,31 @@ public class StatelessSessionStatisticsTest { @Test 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.getEntityUpdateCount()); assertEquals(0, statistics.getEntityDeleteCount()); assertEquals(0, statistics.getEntityLoadCount()); + assertEquals(0, statistics.getPrepareStatementCount()); Person person = new Person(); person.name = "Gavin"; person.handles.add("@1ovthafew"); scope.inStatelessTransaction(s -> s.insert(person)); assertEquals(1, statistics.getEntityInsertCount()); assertEquals(1, statistics.getCollectionRecreateCount()); + assertEquals(stmtCount, statistics.getPrepareStatementCount()); + assertEquals(stmtCount, statistics.getCloseStatementCount()); scope.inStatelessSession(s -> s.get(Person.class, person.id)); assertEquals(1, statistics.getEntityLoadCount()); assertEquals(0, statistics.getEntityFetchCount()); assertEquals(1, statistics.getCollectionLoadCount()); assertEquals(0, statistics.getCollectionFetchCount()); + assertEquals(++stmtCount, statistics.getPrepareStatementCount()); + assertEquals(stmtCount, statistics.getCloseStatementCount()); person.name = "Gavin King"; scope.inStatelessTransaction(s -> s.update(person)); assertEquals(1, statistics.getEntityUpdateCount()); @@ -56,25 +67,37 @@ void test(SessionFactoryScope scope) { assertEquals(2, statistics.getEntityLoadCount()); assertEquals(2, statistics.getCollectionLoadCount()); 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)); assertEquals(3, statistics.getEntityLoadCount()); assertEquals(2, statistics.getCollectionLoadCount()); 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)); assertEquals(4, statistics.getEntityLoadCount()); assertEquals(3, statistics.getCollectionLoadCount()); assertEquals(1, statistics.getCollectionFetchCount()); + assertEquals(stmtCount+=2, statistics.getPrepareStatementCount()); + assertEquals(stmtCount, statistics.getCloseStatementCount()); scope.inStatelessSession(s -> s.createQuery("from Person", Person.class).getSingleResult()); assertEquals(5, statistics.getEntityLoadCount()); assertEquals(4, statistics.getCollectionLoadCount()); assertEquals(2, statistics.getCollectionFetchCount()); + assertEquals(stmtCount+=2, statistics.getPrepareStatementCount()); + assertEquals(stmtCount, statistics.getCloseStatementCount()); person.handles.add("hello world"); scope.inStatelessTransaction(s -> s.upsert(person)); assertEquals(2, statistics.getCollectionUpdateCount()); + assertEquals(stmtCount+=4, statistics.getPrepareStatementCount()); + assertEquals(stmtCount, statistics.getCloseStatementCount()); scope.inStatelessTransaction(s -> s.delete(person)); assertEquals(1, statistics.getEntityDeleteCount()); assertEquals(1, statistics.getCollectionRemoveCount()); assertEquals(4, statistics.getTransactionCount()); + assertEquals(stmtCount+=2, statistics.getPrepareStatementCount()); + assertEquals(stmtCount, statistics.getCloseStatementCount()); } @Entity(name="Person") diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/stats/StatisticsWithNoCachingTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/stats/StatisticsWithNoCachingTest.java index aa432a90d590..fc08b0ce0c00 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/stats/StatisticsWithNoCachingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/stats/StatisticsWithNoCachingTest.java @@ -21,11 +21,11 @@ @DomainModel @SessionFactory @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 static class RegionFacrotySettingProvider implements SettingProvider.Provider { + public static class RegionFactorySettingProvider implements SettingProvider.Provider { @Override public String getSetting() {