A beginner’s guide to Hibernate Statistics
Are you struggling with performance issues in your Spring, Jakarta EE, or Java EE application?
What if there were a tool that could automatically detect what caused performance issues in your JPA and Hibernate data access layer?
Wouldn’t it be awesome to have such a tool to watch your application and prevent performance issues during development, long before they affect production systems?
Well, Hypersistence Optimizer is that tool! And it works with Spring Boot, Spring Framework, Jakarta EE, Java EE, Quarkus, Micronaut, or Play Framework.
So, rather than fixing performance issues in your production system on a Saturday night, you are better off using Hypersistence Optimizer to help you prevent those issues so that you can spend your time on the things that you love!
Introduction
Hibernate provides a very powerful Statistics mechanism that, unfortunately, is lesser known. In this article, we are going to see how the Hibernate Statistics mechanism works, and how you can activate.
While the Hibernate Statistics mechanism is not enabled by default, you will see that many applications can benefit from using it, especially when it comes to determining cache effectiveness.
A beginner’s guide to Hibernate Statistics@vlad_mihalcea https://t.co/OdUcM0A74x pic.twitter.com/CNajj2H9xj
— Java (@java) May 1, 2019
Statistics interface
The Hibernate Statistics class hierarchy looks as follows:

The Hibernate org.hibernate.stat.Statistics interface contains an exhaustive list of metrics you can inspect in regards to the behavior of the current Hibernate SessionFactory or JPA EntityManager.
General-purpose methods
The following Statistics methods are used to describe or control the current Hibernate Statistics object.
boolean isStatisticsEnabled()- It determines whether the Hibernate statistic mechanism is enabled or not.
void setStatisticsEnabled(boolean b)- It enables or disables the Hibernate Statistics mechanism.
void clear()- It removes the current collected metrics.
long getStartTime()- It gets the timestamp when the
Statisticsinstance was instantiated. void logSummary()- It prints a log entry containing the most important metrics.
EntityManager or Session metrics
The following metrics are associated with the current Persistence Context:
long getSessionOpenCount()- It provides the number of
SessionorEntityManagerinstances that were opened by the currentEntityManagerFactoryorSessionFactory. long getSessionCloseCount()- It provides the number of
SessionorEntityManagerinstances that were closed by the currentEntityManagerFactoryorSessionFactory. long getFlushCount()- It provides the number of times the
SessionorEntityManagerinstances were flushed.
Database metrics
The following metrics are associated with either the database connection, transaction or executing statements:
long getConnectCount()- It gives the number of database connections that were acquired by the current
EntityManagerFactoryorSessionFactory. long getSuccessfulTransactionCount()- It gives the number of transactions that were committed by the current
EntityManagerFactoryorSessionFactory. long getTransactionCount()- It gives the number of transactions that were executed by the current
EntityManagerFactoryorSessionFactory. long getPrepareStatementCount()- It provides the number of JDBC
PreparedStatementsthat were created by the currentEntityManagerFactoryorSessionFactory. long getCloseStatementCount()- It provides the number of JDBC statement instances that were closed by the current
EntityManagerFactoryorSessionFactory.
Entity metrics
The following metrics are associated with the JPA or Hibernate entities:
String[] getEntityNames()- It provides the names of all entities that are registered with the current
EntityManagerFactoryorSessionFactory. EntityStatistics getEntityStatistics(String entityName)- It provides you the
EntityStatisticsobject for the provided entity name. long getEntityLoadCount()- It gives you the total number of entities that were loaded (including the one fetched from the first or second-level cache or the database) by the current
EntityManagerFactoryorSessionFactory. long getEntityFetchCount()- It gives you the total number of entities that were fetched from the database by the current
EntityManagerFactoryorSessionFactory. long getEntityInsertCount()- It gives you the total number of entities that were inserted by the current
EntityManagerFactoryorSessionFactory. long getEntityUpdateCount()- It gives you the total number of entities that were updated by the current
EntityManagerFactoryorSessionFactory. long getEntityDeleteCount()- It gives you the total number of entities that were deleted by the current
EntityManagerFactoryorSessionFactory.
Collection metrics
The following metrics are associated with the JPA or Hibernate entity collections:
String[] getCollectionRoleNames()- It provides the names of all entity collections that are registered with the current
EntityManagerFactoryorSessionFactory. CollectionStatistics getCollectionStatistics(String role)- It provides you the
CollectionStatisticsobject for the provided entity collection name. long getCollectionLoadCount()- It gives you the total number of collections that were loaded (including the one fetched from the first or second-level cache or the database) by the current
EntityManagerFactoryorSessionFactory. long getCollectionFetchCount()- It gives you the total number of collections that were fetched from the database by the current
EntityManagerFactoryorSessionFactory. long getCollectionUpdateCount()- It gives you the total number of collections that were updated by the current
EntityManagerFactoryorSessionFactory. long getCollectionRemoveCount()- It gives you the total number of collections that were removed by the current
EntityManagerFactoryorSessionFactory. long getCollectionRecreateCount()- It gives you the total number of collections that were recreated by the current
EntityManagerFactoryorSessionFactory.
Query metrics
The following metrics are associated with the queries that were executed by the current JPA EntityManagerFactory or Hibernate SessionFactory:
String[] getQueries()- It returns the entity queries (e.g. HQL and Criteria API) executed by the current JPA
EntityManagerFactoryor HibernateSessionFactory. QueryStatistics getQueryStatistics(String queryString)- It returns the
QueryStatisticsassociated to the provided query. long getQueryExecutionCount()- It gives the number of queries that were executed by the current JPA
EntityManagerFactoryor HibernateSessionFactory. long getQueryExecutionMaxTime()- It gives the maximum execution time of all queries that were executed.
String getQueryExecutionMaxTimeQueryString()- It gives the name of the query with the longest execution time.
long getQueryPlanCacheHitCount()- It provides the hit count for the Query Plan Cache.
long getQueryPlanCacheMissCount()- It provides the miss count for the Query Plan Cache.
Natural identifier metrics
The following metrics are associated with the Hibernate natural identifier mechanism:
NaturalIdStatistics getNaturalIdStatistics(String entityName)- It returns the
NaturalIdStatisticsassociated with the provided entity name. long getNaturalIdQueryExecutionCount()- It gives the number of times a given entity identifier was resolved by its associated natural id.
long getNaturalIdQueryExecutionMaxTime()- It gives the maximum execution time a given entity identifier was resolved by its associated natural id.
String getNaturalIdQueryExecutionMaxTimeRegion()- It gives the second-level cache region name with the longest natural id resolving query.
String getNaturalIdQueryExecutionMaxTimeEntity()- It gives the entity name for whichthe longest natural id resolving query was recorded.
Second-level cache metrics
The following metrics are associated with the second-level caching mechanism:
String[] getSecondLevelCacheRegionNames()- It provides the names of all regions used by the second-level cache.
CacheRegionStatistics getDomainDataRegionStatistics(String regionName)- It provides the
CacheRegionStatisticsassociated with the given region name. CacheRegionStatistics getQueryRegionStatistics(String regionName)- It provides the query
CacheRegionStatisticsassociated with the given region name. CacheRegionStatistics getCacheRegionStatistics(String regionName)- It provides the domain data or query
CacheRegionStatisticsassociated with the given region name. long getSecondLevelCacheHitCount()- It provides the global hit count of all entity or collection cache regions.
long getSecondLevelCacheMissCount()- It provides the global miss count of all entity or collection cache regions.
long getSecondLevelCachePutCount()- It provides the global put count of all entity or collection cache regions.
long getNaturalIdCacheHitCount()- It provides the global hit count of the natural id cache region.
long getNaturalIdCacheMissCount()- It provides the global miss count of the natural id cache region.
long getNaturalIdCachePutCount()- It provides the global put count of the natural id cache region.
long getQueryCacheHitCount()- It provides the hit count of the query cache region.
long getQueryCacheMissCount()- It provides the miss count of the query cache region.
long getQueryCachePutCount()- It provides the put count of the query cache region.
long getUpdateTimestampsCacheHitCount()- It provides the hit count of the timestamp cache region, which is used by the query cache.
long getUpdateTimestampsCacheMissCount()- It the miss count of the timestamp cache region, which is used by the query cache.
long getUpdateTimestampsCachePutCount()- It provides the global put count of the timestamp cache region, which is used by the query cache.
Concurrency-control metrics
long getOptimisticFailureCount()- It provides the number of optimistic locking failures detected by the current
EntityManagerFactoryorSessionFactory.
StatisticsImplementor interface
The org.hibernate.stat.spi.StatisticsImplementor interface extends the aforementioned Statistics interface and defines multiple callback methods that are executed by the Hibernate core API.
EntityManager or Session metrics
void openSession()- This callback is called when a JPA
EntityManageror the HibernateSessionis created. void closeSession()- This callback is called when a JPA
EntityManageror the HibernateSessionis closed. void flush()- This callback is called when a JPA
EntityManageror the HibernateSessionis flushed.
Database metrics
void connect()- This callback is called when a database connection is acquired from the currently configured
ConnectionProvider. void prepareStatement()- This callback is called when a JDBC
PreparedStatementinstance is created. void closeStatement()- This callback is called when a JDBC
PreparedStatementinstance is closed. void endTransaction(boolean success)- This callback is called when the RESOURCE_LOCAL or JTA transaction is either committed or rolled back.
Entity metrics
void loadEntity(String entityName)- This callback is called when a given entity is loaded either as a Proxy or by fetching it from the database.
void fetchEntity(String entityName)- This callback is called when a given entity is fetched from the database.
void insertEntity(String entityName)- This callback is called when a given entity is inserted.
void updateEntity(String entityName)- This callback is called when a given entity is updated.
void deleteEntity(String entityName)- This callback is called when a given entity is deleted.
Collection metrics
void loadCollection(String role)- This callback is executed when a given entity collection is either created or loaded.
void fetchCollection(String role)- This callback is executed when a given entity collection is fetched from the database.
void updateCollection(String role)- This callback is executed when a given entity collection is updated.
void recreateCollection(String role)- This callback is executed when a given entity collection is recreated.
void removeCollection(String role)- This callback is executed when a given entity collection is removed.
Query metrics
void queryExecuted(String hql, int rows, long time)- This callback is called after an entity or native SQL query is executed.
void queryPlanCacheHit(String hql)- This callback is called when the entity query plan was loaded from the query plan cache.
void queryCompiled(String hql, long microseconds)- This callback is called when the entity query plan could not be loaded from the query plan cache.
Second-level cache metrics
void entityCachePut(NavigableRole entityName, String regionName)- This callback is executed when a given entity is added to the second-level cached.
void entityCacheHit(NavigableRole entityName, String regionName)- This callback is executed when a given entity is loaded from the second-level cached.
void entityCacheMiss(NavigableRole entityName, String regionName)- This callback is executed when a given entity was not found in the second-level cached.
void collectionCachePut(NavigableRole collectionRole, String regionName)- This callback is executed when a given entity collection was added to the second-level cached.
void collectionCacheHit(NavigableRole collectionRole, String regionName)- This callback is executed when a given entity collection is loaded from the second-level cached.
void collectionCacheMiss(NavigableRole collectionRole, String regionName)- This callback is executed when a given entity collection was not found in the second-level cached.
void naturalIdCachePut(NavigableRole rootEntityName, String regionName)- This callback is executed when a given natural id is added to the second-level cached.
void naturalIdCacheHit(NavigableRole rootEntityName, String regionName)- This callback is executed when a given entity identifier is resolved via its associated natural id from the second-level cached.
void naturalIdCacheMiss(NavigableRole rootEntityName, String regionName)- This callback is executed when a given entity identifier could not be resolved via its associated natural id from the second-level cached.
void naturalIdQueryExecuted(String rootEntityName, long executionTime)- This callback is called after the entity identifier query by the associated natural id is executed.
void queryCachePut(String hql, String regionName)- This callback is called when a query cache entry is stored in the second-level query cache region.
void queryCacheHit(String hql, String regionName)- This callback is called when a query cache entry is loaded from the second-level query cache region.
void queryCacheMiss(String hql, String regionName)- This callback is called when a query cache entry could not be loaded from the second-level query cache region.
void updateTimestampsCacheHit()- This callback is called when the tablespace last update timestamp is loaded from the timestamp query cache region
void updateTimestampsCacheMiss()- This callback is called when the tablespace last update timestamp could not be loaded from the timestamp query cache region
void updateTimestampsCachePut()- This callback is called when the tablespace last update timestamp is added to the timestamp query cache region
Concurrency-control metrics
void optimisticFailure(String entityName)- This callback is called when an optimistic locking exception is thrown.
These callbacks are very useful if you want to customize the Hibernate Statistics mechanism.
Activating the statistics mechanism
By default, the statistic mechanism is disabled. To enable it, you need to set the following configuration property:
<property name="hibernate.generate_statistics" value="true"/>
Once activated, the metrics are stored in the org.hibernate.stat.internal.StatisticsImpl object.
To see the statistics printed in the log, you need to set the following logger:
<logger name="org.hibernate.engine.internal.StatisticalLoggingSessionEventListener" level="info"/>
Afterward, Hibernate is going to print the following log entries:
INFO [Alice]: o.h.e.i.StatisticalLoggingSessionEventListener - Session Metrics {
307100 nanoseconds spent acquiring 1 JDBC connections;
55100 nanoseconds spent releasing 1 JDBC connections;
13868600 nanoseconds spent preparing 3 JDBC statements;
3504100 nanoseconds spent executing 3 JDBC statements;
0 nanoseconds spent executing 0 JDBC batches;
0 nanoseconds spent performing 0 L2C puts;
0 nanoseconds spent performing 0 L2C hits;
0 nanoseconds spent performing 0 L2C misses;
53460600 nanoseconds spent executing 1 flushes (flushing a total of 3 entities and 2 collections);
0 nanoseconds spent executing 0 partial-flushes (flushing a total of 0 entities and 0 collections)
Cool, right?
If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.
Conclusion
The statistics mechanism is a very useful way to get a better insight into Hibernate internal workings. While the Statistics object is used to read the metrics, the StatisticsImplementor is useful when you want to customize the way the metrics are collected.






