diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java
index 7c82ff7017..9f4db07d41 100644
--- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java
+++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java
@@ -17,6 +17,9 @@ import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SessionEventListenerManager;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
+import org.hibernate.event.jfr.CachePutEvent;
+import org.hibernate.event.jfr.internal.JfrEventManager;
+import org.hibernate.event.jfr.internal.JfrEventManager.CacheActionDescription;
import org.hibernate.event.service.spi.EventListenerGroup;
import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.PostCommitInsertEventListener;
@@ -161,11 +164,23 @@ public class EntityInsertAction extends AbstractEntityInsertAction {
protected boolean cacheInsert(EntityPersister persister, Object ck) {
SharedSessionContractImplementor session = getSession();
+ final CachePutEvent cachePutEvent = JfrEventManager.beginCachePutEvent();
+ final EntityDataAccess cacheAccessStrategy = persister.getCacheAccessStrategy();
+ boolean insert = false;
try {
session.getEventListenerManager().cachePutStart();
- return persister.getCacheAccessStrategy().insert( session, ck, cacheEntry, version );
+ insert = cacheAccessStrategy.insert( session, ck, cacheEntry, version );
+ return insert;
}
finally {
+ JfrEventManager.completeCachePutEvent(
+ cachePutEvent,
+ session,
+ cacheAccessStrategy,
+ getPersister(),
+ insert,
+ CacheActionDescription.ENTITY_INSERT
+ );
session.getEventListenerManager().cachePutEnd();
}
}
@@ -240,11 +255,22 @@ public class EntityInsertAction extends AbstractEntityInsertAction {
protected boolean cacheAfterInsert(EntityDataAccess cache, Object ck) {
SharedSessionContractImplementor session = getSession();
final SessionEventListenerManager eventListenerManager = session.getEventListenerManager();
+ final CachePutEvent cachePutEvent = JfrEventManager.beginCachePutEvent();
+ boolean afterInsert = false;
try {
eventListenerManager.cachePutStart();
- return cache.afterInsert( session, ck, cacheEntry, version );
+ afterInsert = cache.afterInsert( session, ck, cacheEntry, version );
+ return afterInsert;
}
finally {
+ JfrEventManager.completeCachePutEvent(
+ cachePutEvent,
+ session,
+ cache,
+ getPersister(),
+ afterInsert,
+ CacheActionDescription.ENTITY_AFTER_INSERT
+ );
eventListenerManager.cachePutEnd();
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java
index a1281c391a..e70c79c66e 100644
--- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java
+++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java
@@ -19,6 +19,8 @@ import org.hibernate.engine.spi.SessionEventListenerManager;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.Status;
+import org.hibernate.event.jfr.CachePutEvent;
+import org.hibernate.event.jfr.internal.JfrEventManager;
import org.hibernate.event.service.spi.EventListenerGroup;
import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.PostCommitUpdateEventListener;
@@ -307,11 +309,23 @@ public class EntityUpdateAction extends EntityAction {
protected boolean updateCache(EntityPersister persister, Object previousVersion, Object ck) {
final SharedSessionContractImplementor session = getSession();
+ final CachePutEvent cachePutEvent = JfrEventManager.beginCachePutEvent();
+ final EntityDataAccess cacheAccessStrategy = persister.getCacheAccessStrategy();
+ boolean update = false;
try {
session.getEventListenerManager().cachePutStart();
- return persister.getCacheAccessStrategy().update( session, ck, cacheEntry, nextVersion, previousVersion );
+ update = cacheAccessStrategy.update( session, ck, cacheEntry, nextVersion, previousVersion );
+ return update;
}
finally {
+ JfrEventManager.completeCachePutEvent(
+ cachePutEvent,
+ session,
+ cacheAccessStrategy,
+ getPersister(),
+ update,
+ JfrEventManager.CacheActionDescription.ENTITY_UPDATE
+ );
session.getEventListenerManager().cachePutEnd();
}
}
@@ -420,10 +434,21 @@ public class EntityUpdateAction extends EntityAction {
protected void cacheAfterUpdate(EntityDataAccess cache, Object ck, SharedSessionContractImplementor session) {
final SessionEventListenerManager eventListenerManager = session.getEventListenerManager();
+ final CachePutEvent cachePutEvent = JfrEventManager.beginCachePutEvent();
+ boolean put = false;
try {
eventListenerManager.cachePutStart();
- boolean put = cache.afterUpdate( session, ck, cacheEntry, nextVersion, previousVersion, lock );
-
+ put = cache.afterUpdate( session, ck, cacheEntry, nextVersion, previousVersion, lock );
+ }
+ finally {
+ JfrEventManager.completeCachePutEvent(
+ cachePutEvent,
+ session,
+ cache,
+ getPersister(),
+ put,
+ JfrEventManager.CacheActionDescription.ENTITY_AFTER_UPDATE
+ );
final StatisticsImplementor statistics = session.getFactory().getStatistics();
if ( put && statistics.isStatisticsEnabled() ) {
statistics.entityCachePut(
@@ -431,8 +456,6 @@ public class EntityUpdateAction extends EntityAction {
cache.getRegion().getName()
);
}
- }
- finally {
eventListenerManager.cachePutEnd();
}
diff --git a/hibernate-core/src/main/java/org/hibernate/cache/internal/QueryResultsCacheImpl.java b/hibernate-core/src/main/java/org/hibernate/cache/internal/QueryResultsCacheImpl.java
index 6f4ed38aa9..d903ae0c25 100644
--- a/hibernate-core/src/main/java/org/hibernate/cache/internal/QueryResultsCacheImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/cache/internal/QueryResultsCacheImpl.java
@@ -17,6 +17,9 @@ import org.hibernate.cache.spi.QueryResultsCache;
import org.hibernate.cache.spi.QueryResultsRegion;
import org.hibernate.cache.spi.TimestampsCache;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
+import org.hibernate.event.jfr.CacheGetEvent;
+import org.hibernate.event.jfr.CachePutEvent;
+import org.hibernate.event.jfr.internal.JfrEventManager;
import static org.hibernate.cache.spi.SecondLevelCacheLogger.L2CACHE_LOGGER;
@@ -61,11 +64,19 @@ public class QueryResultsCacheImpl implements QueryResultsCache {
deepCopy( results )
);
+ final CachePutEvent cachePutEvent = JfrEventManager.beginCachePutEvent();
try {
session.getEventListenerManager().cachePutStart();
cacheRegion.putIntoCache( key, cacheItem, session );
}
finally {
+ JfrEventManager.completeCachePutEvent(
+ cachePutEvent,
+ session,
+ cacheRegion,
+ true,
+ JfrEventManager.CacheActionDescription.QUERY_RESULT
+ );
session.getEventListenerManager().cachePutEnd();
}
@@ -142,11 +153,18 @@ public class QueryResultsCacheImpl implements QueryResultsCache {
private CacheItem getCachedData(QueryKey key, SharedSessionContractImplementor session) {
CacheItem cachedItem = null;
+ final CacheGetEvent cacheGetEvent = JfrEventManager.beginCacheGetEvent();
try {
session.getEventListenerManager().cacheGetStart();
cachedItem = (CacheItem) cacheRegion.getFromCache( key, session );
}
finally {
+ JfrEventManager.completeCacheGetEvent(
+ cacheGetEvent,
+ session,
+ cacheRegion,
+ cachedItem != null
+ );
session.getEventListenerManager().cacheGetEnd( cachedItem != null );
}
return cachedItem;
diff --git a/hibernate-core/src/main/java/org/hibernate/cache/internal/TimestampsCacheEnabledImpl.java b/hibernate-core/src/main/java/org/hibernate/cache/internal/TimestampsCacheEnabledImpl.java
index e6be0dfe27..7559d9ba76 100644
--- a/hibernate-core/src/main/java/org/hibernate/cache/internal/TimestampsCacheEnabledImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/cache/internal/TimestampsCacheEnabledImpl.java
@@ -14,6 +14,9 @@ import org.hibernate.cache.spi.TimestampsRegion;
import org.hibernate.engine.spi.SessionEventListenerManager;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
+import org.hibernate.event.jfr.CacheGetEvent;
+import org.hibernate.event.jfr.CachePutEvent;
+import org.hibernate.event.jfr.internal.JfrEventManager;
import org.hibernate.stat.spi.StatisticsImplementor;
import org.jboss.logging.Logger;
@@ -58,7 +61,7 @@ public class TimestampsCacheEnabledImpl implements TimestampsCache {
if ( debugEnabled ) {
log.debugf( "Pre-invalidating space [%s], timestamp: %s", space, ts );
}
-
+ final CachePutEvent cachePutEvent = JfrEventManager.beginCachePutEvent();
try {
eventListenerManager.cachePutStart();
@@ -67,6 +70,13 @@ public class TimestampsCacheEnabledImpl implements TimestampsCache {
timestampsRegion.putIntoCache( space, ts, session );
}
finally {
+ JfrEventManager.completeCachePutEvent(
+ cachePutEvent,
+ session,
+ timestampsRegion,
+ true,
+ JfrEventManager.CacheActionDescription.TIMESTAMP_PRE_INVALIDATE
+ );
eventListenerManager.cachePutEnd();
}
@@ -92,11 +102,19 @@ public class TimestampsCacheEnabledImpl implements TimestampsCache {
}
final SessionEventListenerManager eventListenerManager = session.getEventListenerManager();
+ final CachePutEvent cachePutEvent = JfrEventManager.beginCachePutEvent();
try {
eventListenerManager.cachePutStart();
timestampsRegion.putIntoCache( space, ts, session );
}
finally {
+ JfrEventManager.completeCachePutEvent(
+ cachePutEvent,
+ session,
+ timestampsRegion,
+ true,
+ JfrEventManager.CacheActionDescription.TIMESTAMP_INVALIDATE
+ );
eventListenerManager.cachePutEnd();
if ( stats ) {
@@ -175,11 +193,18 @@ public class TimestampsCacheEnabledImpl implements TimestampsCache {
private Long getLastUpdateTimestampForSpace(String space, SharedSessionContractImplementor session) {
Long ts = null;
+ final CacheGetEvent cacheGetEvent = JfrEventManager.beginCacheGetEvent();
try {
session.getEventListenerManager().cacheGetStart();
ts = (Long) timestampsRegion.getFromCache( space, session );
}
finally {
+ JfrEventManager.completeCacheGetEvent(
+ cacheGetEvent,
+ session,
+ timestampsRegion,
+ ts != null
+ );
session.getEventListenerManager().cacheGetEnd( ts != null );
}
return ts;
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/CacheHelper.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/CacheHelper.java
index 0e3543d1ef..84e67cb340 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/internal/CacheHelper.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/CacheHelper.java
@@ -12,7 +12,11 @@ import org.hibernate.cache.MutableCacheKeyBuilder;
import org.hibernate.cache.spi.access.CachedDomainDataAccess;
import org.hibernate.engine.spi.SessionEventListenerManager;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
+import org.hibernate.event.jfr.CacheGetEvent;
+import org.hibernate.event.jfr.internal.JfrEventManager;
import org.hibernate.metamodel.mapping.JdbcMapping;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
import org.hibernate.type.descriptor.java.JavaType;
@@ -28,14 +32,58 @@ public final class CacheHelper {
public static Object fromSharedCache(
SharedSessionContractImplementor session,
Object cacheKey,
+ EntityPersister persister,
+ CachedDomainDataAccess cacheAccess) {
+ return fromSharedCache( session, cacheKey, persister, false, cacheAccess );
+ }
+
+ public static Object fromSharedCache(
+ SharedSessionContractImplementor session,
+ Object cacheKey,
+ EntityPersister persister,
+ boolean isNaturalKey,
CachedDomainDataAccess cacheAccess) {
final SessionEventListenerManager eventListenerManager = session.getEventListenerManager();
Object cachedValue = null;
eventListenerManager.cacheGetStart();
+ final CacheGetEvent cacheGetEvent = JfrEventManager.beginCacheGetEvent();
try {
cachedValue = cacheAccess.get( session, cacheKey );
}
finally {
+ JfrEventManager.completeCacheGetEvent(
+ cacheGetEvent,
+ session,
+ cacheAccess.getRegion(),
+ persister,
+ isNaturalKey,
+ cachedValue != null
+ );
+ eventListenerManager.cacheGetEnd( cachedValue != null );
+ }
+ return cachedValue;
+ }
+
+ public static Object fromSharedCache(
+ SharedSessionContractImplementor session,
+ Object cacheKey,
+ CollectionPersister persister,
+ CachedDomainDataAccess cacheAccess) {
+ final SessionEventListenerManager eventListenerManager = session.getEventListenerManager();
+ Object cachedValue = null;
+ eventListenerManager.cacheGetStart();
+ final CacheGetEvent cacheGetEvent = JfrEventManager.beginCacheGetEvent();
+ try {
+ cachedValue = cacheAccess.get( session, cacheKey );
+ }
+ finally {
+ JfrEventManager.completeCacheGetEvent(
+ cacheGetEvent,
+ session,
+ cacheAccess.getRegion(),
+ persister,
+ cachedValue != null
+ );
eventListenerManager.cacheGetEnd( cachedValue != null );
}
return cachedValue;
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/NaturalIdResolutionsImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/NaturalIdResolutionsImpl.java
index de7197502b..dba4c1e05e 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/internal/NaturalIdResolutionsImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/NaturalIdResolutionsImpl.java
@@ -23,6 +23,8 @@ import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.Resolution;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
+import org.hibernate.event.jfr.CachePutEvent;
+import org.hibernate.event.jfr.internal.JfrEventManager;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.NaturalIdLogging;
import org.hibernate.metamodel.mapping.NaturalIdMapping;
@@ -268,32 +270,63 @@ public class NaturalIdResolutionsImpl implements NaturalIdResolutions, Serializa
switch ( source ) {
case LOAD: {
- if ( CacheHelper.fromSharedCache( s, cacheKey, cacheAccess ) != null ) {
+ if ( CacheHelper.fromSharedCache( s, cacheKey, persister, cacheAccess ) != null ) {
// prevent identical re-cachings
return;
}
- final boolean put = cacheAccess.putFromLoad(
- s,
- cacheKey,
- id,
- null
- );
+ boolean put = false;
+ final CachePutEvent cachePutEvent = JfrEventManager.beginCachePutEvent();
+ try {
+ put = cacheAccess.putFromLoad(
+ s,
+ cacheKey,
+ id,
+ null
+ );
- if ( put && statistics.isStatisticsEnabled() ) {
- statistics.naturalIdCachePut(
- rootEntityDescriptor.getNavigableRole(),
- cacheAccess.getRegion().getName()
+ if ( put && statistics.isStatisticsEnabled() ) {
+ statistics.naturalIdCachePut(
+ rootEntityDescriptor.getNavigableRole(),
+ cacheAccess.getRegion().getName()
+ );
+ }
+ }
+ finally {
+ JfrEventManager.completeCachePutEvent(
+ cachePutEvent,
+ session(),
+ cacheAccess,
+ rootEntityPersister,
+ put,
+ true,
+ JfrEventManager.CacheActionDescription.ENTITY_LOAD
);
}
break;
}
case INSERT: {
- final boolean put = cacheAccess.insert( s, cacheKey, id );
- if ( put && statistics.isStatisticsEnabled() ) {
- statistics.naturalIdCachePut(
- rootEntityDescriptor.getNavigableRole(),
- cacheAccess.getRegion().getName()
+ boolean put = false;
+ final CachePutEvent cachePutEvent = JfrEventManager.beginCachePutEvent();
+
+ try {
+ put = cacheAccess.insert( s, cacheKey, id );
+ if ( put && statistics.isStatisticsEnabled() ) {
+ statistics.naturalIdCachePut(
+ rootEntityDescriptor.getNavigableRole(),
+ cacheAccess.getRegion().getName()
+ );
+ }
+ }
+ finally {
+ JfrEventManager.completeCachePutEvent(
+ cachePutEvent,
+ session(),
+ cacheAccess,
+ rootEntityPersister,
+ put,
+ true,
+ JfrEventManager.CacheActionDescription.ENTITY_INSERT
);
}
@@ -326,11 +359,26 @@ public class NaturalIdResolutionsImpl implements NaturalIdResolutions, Serializa
cacheAccess.remove( s, previousCacheKey);
final SoftLock lock = cacheAccess.lockItem( s, cacheKey, null );
- final boolean put = cacheAccess.update( s, cacheKey, id );
- if ( put && statistics.isStatisticsEnabled() ) {
- statistics.naturalIdCachePut(
- rootEntityDescriptor.getNavigableRole(),
- cacheAccess.getRegion().getName()
+ boolean put = false;
+ final CachePutEvent cachePutEvent = JfrEventManager.beginCachePutEvent();
+ try {
+ put = cacheAccess.update( s, cacheKey, id );
+ if ( put && statistics.isStatisticsEnabled() ) {
+ statistics.naturalIdCachePut(
+ rootEntityDescriptor.getNavigableRole(),
+ cacheAccess.getRegion().getName()
+ );
+ }
+ }
+ finally {
+ JfrEventManager.completeCachePutEvent(
+ cachePutEvent,
+ session(),
+ cacheAccess,
+ rootEntityPersister,
+ put,
+ true,
+ JfrEventManager.CacheActionDescription.ENTITY_UPDATE
);
}
@@ -338,17 +386,32 @@ public class NaturalIdResolutionsImpl implements NaturalIdResolutions, Serializa
(success, session) -> {
cacheAccess.unlockItem( s, previousCacheKey, removalLock );
if (success) {
- final boolean put12 = cacheAccess.afterUpdate(
- s,
- cacheKey,
- id,
- lock
- );
+ boolean putAfterUpdate = false;
+ final CachePutEvent cachePutEventAfterUpdate = JfrEventManager.beginCachePutEvent();
+ try {
+ putAfterUpdate = cacheAccess.afterUpdate(
+ s,
+ cacheKey,
+ id,
+ lock
+ );
- if ( put12 && statistics.isStatisticsEnabled() ) {
- statistics.naturalIdCachePut(
- rootEntityDescriptor.getNavigableRole(),
- cacheAccess.getRegion().getName()
+ if ( putAfterUpdate && statistics.isStatisticsEnabled() ) {
+ statistics.naturalIdCachePut(
+ rootEntityDescriptor.getNavigableRole(),
+ cacheAccess.getRegion().getName()
+ );
+ }
+ }
+ finally {
+ JfrEventManager.completeCachePutEvent(
+ cachePutEventAfterUpdate,
+ session(),
+ cacheAccess,
+ rootEntityPersister,
+ putAfterUpdate,
+ true,
+ JfrEventManager.CacheActionDescription.ENTITY_AFTER_UPDATE
);
}
}
@@ -567,7 +630,7 @@ public class NaturalIdResolutionsImpl implements NaturalIdResolutions, Serializa
final SharedSessionContractImplementor session = session();
final Object naturalIdCacheKey = naturalIdCacheAccessStrategy.generateCacheKey( naturalId, persister, session );
- pk = CacheHelper.fromSharedCache( session, naturalIdCacheKey, naturalIdCacheAccessStrategy );
+ pk = CacheHelper.fromSharedCache( session, naturalIdCacheKey, persister, true, naturalIdCacheAccessStrategy );
// Found in second-level cache, store in session cache
final SessionFactoryImplementor factory = session.getFactory();
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchImpl.java
index ca5733b8b6..d80c1912df 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchImpl.java
@@ -22,6 +22,8 @@ import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
+import org.hibernate.event.jfr.JdbcBatchExecutionEvent;
+import org.hibernate.event.jfr.internal.JfrEventManager;
import org.hibernate.resource.jdbc.spi.JdbcObserver;
import static org.hibernate.engine.jdbc.JdbcLogging.JDBC_MESSAGE_LOGGER;
@@ -268,11 +270,13 @@ public class BatchImpl implements Batch {
try {
if ( statementDetails.getMutatingTableDetails().isIdentifierTable() ) {
final int[] rowCounts;
+ final JdbcBatchExecutionEvent jdbcBatchExecutionEvent = JfrEventManager.beginJdbcBatchExecutionEvent();
try {
observer.jdbcExecuteBatchStart();
rowCounts = statement.executeBatch();
}
finally {
+ JfrEventManager.completeJdbcBatchExecutionEvent( jdbcBatchExecutionEvent, sql );
observer.jdbcExecuteBatchEnd();
}
checkRowCounts( rowCounts, statementDetails );
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/MutationStatementPreparerImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/MutationStatementPreparerImpl.java
index fb8bc5f0c0..58e0f0bfea 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/MutationStatementPreparerImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/MutationStatementPreparerImpl.java
@@ -14,6 +14,8 @@ import org.hibernate.AssertionFailure;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.jdbc.spi.MutationStatementPreparer;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
+import org.hibernate.event.jfr.internal.JfrEventManager;
+import org.hibernate.event.jfr.JdbcPreparedStatementCreationEvent;
import org.hibernate.resource.jdbc.spi.JdbcObserver;
import org.hibernate.resource.jdbc.spi.JdbcSessionContext;
import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor;
@@ -95,12 +97,14 @@ public class MutationStatementPreparerImpl implements MutationStatementPreparer
final JdbcObserver observer = jdbcCoordinator.getJdbcSessionOwner()
.getJdbcSessionContext()
.getObserver();
+ final JdbcPreparedStatementCreationEvent jdbcPreparedStatementCreation = JfrEventManager.beginJdbcPreparedStatementCreationEvent();
try {
observer.jdbcPrepareStatementStart();
preparedStatement = doPrepare();
setStatementTimeout( preparedStatement );
}
finally {
+ JfrEventManager.completeJdbcPreparedStatementCreationEvent( jdbcPreparedStatementCreation, sql );
observer.jdbcPrepareStatementEnd();
}
postProcess( preparedStatement );
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/ResultSetReturnImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/ResultSetReturnImpl.java
index 3f500532cc..2a7ddd97bd 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/ResultSetReturnImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/ResultSetReturnImpl.java
@@ -18,6 +18,8 @@ import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.jdbc.spi.ResultSetReturn;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
+import org.hibernate.event.jfr.JdbcPreparedStatementExecutionEvent;
+import org.hibernate.event.jfr.internal.JfrEventManager;
import org.hibernate.resource.jdbc.spi.JdbcSessionContext;
/**
@@ -44,31 +46,6 @@ public class ResultSetReturnImpl implements ResultSetReturn {
this.sqlExceptionHelper = jdbcServices.getSqlExceptionHelper();
}
- @Override
- public ResultSet extract(PreparedStatement statement) {
- // IMPL NOTE : SQL logged by caller
- long executeStartNanos = 0;
- if ( this.sqlStatementLogger.getLogSlowQuery() > 0 ) {
- executeStartNanos = System.nanoTime();
- }
- try {
- final ResultSet rs;
- try {
- jdbcExecuteStatementStart();
- rs = statement.executeQuery();
- }
- finally {
- jdbcExecuteStatementEnd();
- sqlStatementLogger.logSlowQuery( statement, executeStartNanos, context() );
- }
- postExtract( rs, statement );
- return rs;
- }
- catch (SQLException e) {
- throw sqlExceptionHelper.convert( e, "could not extract ResultSet" );
- }
- }
-
@Override
public ResultSet extract(PreparedStatement statement, String sql) {
// IMPL NOTE : SQL logged by caller
@@ -78,11 +55,13 @@ public class ResultSetReturnImpl implements ResultSetReturn {
}
try {
final ResultSet rs;
+ final JdbcPreparedStatementExecutionEvent jdbcPreparedStatementExecutionEvent = JfrEventManager.beginJdbcPreparedStatementExecutionEvent();
try {
jdbcExecuteStatementStart();
rs = statement.executeQuery();
}
finally {
+ JfrEventManager.completeJdbcPreparedStatementExecutionEvent( jdbcPreparedStatementExecutionEvent, sql );
jdbcExecuteStatementEnd();
sqlStatementLogger.logSlowQuery( sql, executeStartNanos, context() );
}
@@ -106,31 +85,6 @@ public class ResultSetReturnImpl implements ResultSetReturn {
jdbcCoordinator.getJdbcSessionOwner().getJdbcSessionContext().getObserver().jdbcExecuteStatementStart();
}
- @Override
- public ResultSet extract(CallableStatement callableStatement) {
- // IMPL NOTE : SQL logged by caller
- long executeStartNanos = 0;
- if ( this.sqlStatementLogger.getLogSlowQuery() > 0 ) {
- executeStartNanos = System.nanoTime();
- }
- try {
- final ResultSet rs;
- try {
- jdbcExecuteStatementStart();
- rs = dialect.getResultSet( callableStatement );
- }
- finally {
- jdbcExecuteStatementEnd();
- sqlStatementLogger.logSlowQuery( callableStatement, executeStartNanos, context() );
- }
- postExtract( rs, callableStatement );
- return rs;
- }
- catch (SQLException e) {
- throw sqlExceptionHelper.convert( e, "could not extract ResultSet" );
- }
- }
-
@Override
public ResultSet extract(Statement statement, String sql) {
sqlStatementLogger.logStatement( sql );
@@ -140,11 +94,13 @@ public class ResultSetReturnImpl implements ResultSetReturn {
}
try {
final ResultSet rs;
+ final JdbcPreparedStatementExecutionEvent jdbcPreparedStatementExecutionEvent = JfrEventManager.beginJdbcPreparedStatementExecutionEvent();
try {
jdbcExecuteStatementStart();
rs = statement.executeQuery( sql );
}
finally {
+ JfrEventManager.completeJdbcPreparedStatementExecutionEvent( jdbcPreparedStatementExecutionEvent, sql );
jdbcExecuteStatementEnd();
sqlStatementLogger.logSlowQuery( sql, executeStartNanos, context() );
}
@@ -156,36 +112,6 @@ public class ResultSetReturnImpl implements ResultSetReturn {
}
}
- @Override
- public ResultSet execute(PreparedStatement statement) {
- // sql logged by StatementPreparerImpl
- long executeStartNanos = 0;
- if ( this.sqlStatementLogger.getLogSlowQuery() > 0 ) {
- executeStartNanos = System.nanoTime();
- }
- try {
- final ResultSet rs;
- try {
- jdbcExecuteStatementStart();
- if ( !statement.execute() ) {
- while ( !statement.getMoreResults() && statement.getUpdateCount() != -1 ) {
- // do nothing until we hit the resultset
- }
- }
- rs = statement.getResultSet();
- }
- finally {
- jdbcExecuteStatementEnd();
- sqlStatementLogger.logSlowQuery( statement, executeStartNanos, context() );
- }
- postExtract( rs, statement );
- return rs;
- }
- catch (SQLException e) {
- throw sqlExceptionHelper.convert( e, "could not execute statement" );
- }
- }
-
@Override
public ResultSet execute(PreparedStatement statement, String sql) {
// sql logged by StatementPreparerImpl
@@ -195,6 +121,7 @@ public class ResultSetReturnImpl implements ResultSetReturn {
}
try {
final ResultSet rs;
+ final JdbcPreparedStatementExecutionEvent jdbcPreparedStatementExecutionEvent = JfrEventManager.beginJdbcPreparedStatementExecutionEvent();
try {
jdbcExecuteStatementStart();
if ( !statement.execute() ) {
@@ -205,6 +132,7 @@ public class ResultSetReturnImpl implements ResultSetReturn {
rs = statement.getResultSet();
}
finally {
+ JfrEventManager.completeJdbcPreparedStatementExecutionEvent( jdbcPreparedStatementExecutionEvent, sql );
jdbcExecuteStatementEnd();
sqlStatementLogger.logSlowQuery( sql, executeStartNanos, context() );
}
@@ -225,6 +153,7 @@ public class ResultSetReturnImpl implements ResultSetReturn {
}
try {
final ResultSet rs;
+ final JdbcPreparedStatementExecutionEvent jdbcPreparedStatementExecutionEvent = JfrEventManager.beginJdbcPreparedStatementExecutionEvent();
try {
jdbcExecuteStatementStart();
if ( !statement.execute( sql ) ) {
@@ -235,6 +164,7 @@ public class ResultSetReturnImpl implements ResultSetReturn {
rs = statement.getResultSet();
}
finally {
+ JfrEventManager.completeJdbcPreparedStatementExecutionEvent( jdbcPreparedStatementExecutionEvent, sql );
jdbcExecuteStatementEnd();
sqlStatementLogger.logSlowQuery( sql, executeStartNanos, context() );
}
@@ -246,27 +176,6 @@ public class ResultSetReturnImpl implements ResultSetReturn {
}
}
- @Override
- public int executeUpdate(PreparedStatement statement) {
- assert statement != null;
-
- long executeStartNanos = 0;
- if ( this.sqlStatementLogger.getLogSlowQuery() > 0 ) {
- executeStartNanos = System.nanoTime();
- }
- try {
- jdbcExecuteStatementStart();
- return statement.executeUpdate();
- }
- catch (SQLException e) {
- throw sqlExceptionHelper.convert( e, "could not execute statement" );
- }
- finally {
- jdbcExecuteStatementEnd();
- sqlStatementLogger.logSlowQuery( statement, executeStartNanos, context() );
- }
- }
-
@Override
public int executeUpdate(PreparedStatement statement, String sql) {
assert statement != null;
@@ -275,6 +184,7 @@ public class ResultSetReturnImpl implements ResultSetReturn {
if ( this.sqlStatementLogger.getLogSlowQuery() > 0 ) {
executeStartNanos = System.nanoTime();
}
+ final JdbcPreparedStatementExecutionEvent jdbcPreparedStatementExecutionEvent = JfrEventManager.beginJdbcPreparedStatementExecutionEvent();
try {
jdbcExecuteStatementStart();
return statement.executeUpdate();
@@ -283,6 +193,7 @@ public class ResultSetReturnImpl implements ResultSetReturn {
throw sqlExceptionHelper.convert( e, "could not execute statement", sql );
}
finally {
+ JfrEventManager.completeJdbcPreparedStatementExecutionEvent( jdbcPreparedStatementExecutionEvent, sql );
jdbcExecuteStatementEnd();
sqlStatementLogger.logSlowQuery( sql, executeStartNanos, context() );
}
@@ -295,6 +206,7 @@ public class ResultSetReturnImpl implements ResultSetReturn {
if ( this.sqlStatementLogger.getLogSlowQuery() > 0 ) {
executeStartNanos = System.nanoTime();
}
+ final JdbcPreparedStatementExecutionEvent jdbcPreparedStatementExecutionEvent = JfrEventManager.beginJdbcPreparedStatementExecutionEvent();
try {
jdbcExecuteStatementStart();
return statement.executeUpdate( sql );
@@ -303,6 +215,7 @@ public class ResultSetReturnImpl implements ResultSetReturn {
throw sqlExceptionHelper.convert( e, "could not execute statement", sql );
}
finally {
+ JfrEventManager.completeJdbcPreparedStatementExecutionEvent( jdbcPreparedStatementExecutionEvent, sql );
jdbcExecuteStatementEnd();
sqlStatementLogger.logSlowQuery( sql, executeStartNanos, context() );
}
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/StatementPreparerImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/StatementPreparerImpl.java
index d7250a2c21..ac3f6795c3 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/StatementPreparerImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/StatementPreparerImpl.java
@@ -17,6 +17,8 @@ import org.hibernate.ScrollMode;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.engine.jdbc.spi.StatementPreparer;
+import org.hibernate.event.jfr.internal.JfrEventManager;
+import org.hibernate.event.jfr.JdbcPreparedStatementCreationEvent;
import org.hibernate.resource.jdbc.spi.JdbcObserver;
import org.hibernate.resource.jdbc.spi.JdbcSessionContext;
import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor;
@@ -172,12 +174,14 @@ class StatementPreparerImpl implements StatementPreparer {
final PreparedStatement preparedStatement;
final JdbcObserver observer = jdbcCoordinator.getJdbcSessionOwner().getJdbcSessionContext().getObserver();
+ final JdbcPreparedStatementCreationEvent jdbcPreparedStatementCreation = JfrEventManager.beginJdbcPreparedStatementCreationEvent();
try {
observer.jdbcPrepareStatementStart();
preparedStatement = doPrepare();
setStatementTimeout( preparedStatement );
}
finally {
+ JfrEventManager.completeJdbcPreparedStatementCreationEvent( jdbcPreparedStatementCreation, sql );
observer.jdbcPrepareStatementEnd();
}
postProcess( preparedStatement );
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/spi/ResultSetReturn.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/spi/ResultSetReturn.java
index 2bab3a03a1..5b8f7d1d38 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/spi/ResultSetReturn.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/spi/ResultSetReturn.java
@@ -24,21 +24,6 @@ import java.sql.Statement;
*/
public interface ResultSetReturn {
- /**
- * Extract the {@link ResultSet} from the {@link PreparedStatement}.
- *
- * If client passes {@link CallableStatement} reference, this method calls {@link #extract(CallableStatement)}
- * internally. Otherwise, {@link PreparedStatement#executeQuery()} is called.
- *
- * @param statement The {@link PreparedStatement} from which to extract the {@link ResultSet}
- *
- * @return The extracted ResultSet
- *
- * @deprecated Use {@link #extract(PreparedStatement, String)} instead
- */
- @Deprecated(forRemoval = true)
- ResultSet extract(PreparedStatement statement);
-
/**
* Extract the {@link ResultSet} from the {@link PreparedStatement}.
*
@@ -51,20 +36,6 @@ public interface ResultSetReturn {
*/
ResultSet extract(PreparedStatement statement, String sql);
- /**
- * Extract the {@link ResultSet} from the {@link CallableStatement}. Note that this is the limited legacy
- * form which delegates to {@link org.hibernate.dialect.Dialect#getResultSet}. Better option is to integrate
- * {@link org.hibernate.procedure.ProcedureCall}-like hooks
- *
- * @param callableStatement The {@link CallableStatement} from which to extract the {@link ResultSet}
- *
- * @return The extracted {@link ResultSet}
- *
- * @deprecated Use {@link #extract(PreparedStatement, String)} instead
- */
- @Deprecated(forRemoval = true)
- ResultSet extract(CallableStatement callableStatement);
-
/**
* Performs the given SQL statement, expecting a {@link ResultSet} in return
*
@@ -75,19 +46,6 @@ public interface ResultSetReturn {
*/
ResultSet extract(Statement statement, String sql);
- /**
- * Execute the {@link PreparedStatement} return its first {@link ResultSet}, if any.
- * If there is no {@link ResultSet}, returns {@code null}
- *
- * @param statement The {@link PreparedStatement} to execute
- *
- * @return The extracted {@link ResultSet}, or {@code null}
- *
- * @deprecated Use {@link #execute(PreparedStatement, String)} instead
- */
- @Deprecated(forRemoval = true)
- ResultSet execute(PreparedStatement statement);
-
/**
* Execute the {@link PreparedStatement} return its first {@link ResultSet}, if any.
* If there is no {@link ResultSet}, returns {@code null}
@@ -110,18 +68,6 @@ public interface ResultSetReturn {
*/
ResultSet execute(Statement statement, String sql);
- /**
- * Execute the {@link PreparedStatement}, returning its "affected row count".
- *
- * @param statement The {@link PreparedStatement} to execute
- *
- * @return The {@link PreparedStatement#executeUpdate()} result
- *
- * @deprecated Use {@link #executeUpdate(PreparedStatement, String)} instead
- */
- @Deprecated(forRemoval = true)
- int executeUpdate(PreparedStatement statement);
-
/**
* Execute the {@link PreparedStatement}, returning its "affected row count".
*
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/BatchFetchQueue.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/BatchFetchQueue.java
index 7aa6a6c48d..f28544307f 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/spi/BatchFetchQueue.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/BatchFetchQueue.java
@@ -311,7 +311,7 @@ public class BatchFetchQueue {
session.getFactory(),
session.getTenantIdentifier()
);
- return CacheHelper.fromSharedCache( session, key, cache ) != null;
+ return CacheHelper.fromSharedCache( session, key, persister, cache ) != null;
}
return false;
}
@@ -529,7 +529,7 @@ public class BatchFetchQueue {
session.getFactory(),
session.getTenantIdentifier()
);
- return CacheHelper.fromSharedCache( session, cacheKey, cache ) != null;
+ return CacheHelper.fromSharedCache( session, cacheKey, persister, cache ) != null;
}
return false;
}
diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultAutoFlushEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultAutoFlushEventListener.java
index 60a972b0cb..05c958a7c0 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultAutoFlushEventListener.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultAutoFlushEventListener.java
@@ -11,6 +11,8 @@ import org.hibernate.HibernateException;
import org.hibernate.engine.spi.ActionQueue;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SessionEventListenerManager;
+import org.hibernate.event.jfr.PartialFlushEvent;
+import org.hibernate.event.jfr.internal.JfrEventManager;
import org.hibernate.event.spi.AutoFlushEvent;
import org.hibernate.event.spi.AutoFlushEventListener;
import org.hibernate.event.spi.EventSource;
@@ -37,6 +39,7 @@ public class DefaultAutoFlushEventListener extends AbstractFlushingEventListener
public void onAutoFlush(AutoFlushEvent event) throws HibernateException {
final EventSource source = event.getSession();
final SessionEventListenerManager eventListenerManager = source.getEventListenerManager();
+ final PartialFlushEvent partialFlushEvent = JfrEventManager.beginPartialFlushEvent();
try {
eventListenerManager.partialFlushStart();
@@ -52,11 +55,16 @@ public class DefaultAutoFlushEventListener extends AbstractFlushingEventListener
// note: performExecutions() clears all collectionXxxxtion
// collections (the collection actions) in the session
- performExecutions( source );
- postFlush( source );
-
- postPostFlush( source );
+ final org.hibernate.event.jfr.FlushEvent jfrFlushEvent = JfrEventManager.beginFlushEvent();
+ try {
+ performExecutions( source );
+ postFlush( source );
+ postPostFlush( source );
+ }
+ finally {
+ JfrEventManager.completeFlushEvent( jfrFlushEvent, event, true );
+ }
final StatisticsImplementor statistics = source.getFactory().getStatistics();
if ( statistics.isStatisticsEnabled() ) {
statistics.flush();
@@ -70,6 +78,7 @@ public class DefaultAutoFlushEventListener extends AbstractFlushingEventListener
}
}
finally {
+ JfrEventManager.completePartialFlushEvent( partialFlushEvent, event );
eventListenerManager.partialFlushEnd(
event.getNumberOfEntitiesProcessed(),
event.getNumberOfEntitiesProcessed()
diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultFlushEntityEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultFlushEntityEventListener.java
index de2b6c0453..566424b6e4 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultFlushEntityEventListener.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultFlushEntityEventListener.java
@@ -24,6 +24,8 @@ import org.hibernate.engine.spi.SelfDirtinessTracker;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.Status;
+import org.hibernate.event.jfr.DirtyCalculationEvent;
+import org.hibernate.event.jfr.internal.JfrEventManager;
import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.FlushEntityEvent;
import org.hibernate.event.spi.FlushEntityEventListener;
@@ -482,11 +484,12 @@ public class DefaultFlushEntityEventListener implements FlushEntityEventListener
final SessionImplementor session = event.getSession();
boolean dirtyCheckPossible;
int[] dirtyProperties = null;
+ final DirtyCalculationEvent dirtyCalculationEvent = JfrEventManager.beginDirtyCalculationEvent();
+ final EntityEntry entry = event.getEntityEntry();
+ final EntityPersister persister = entry.getPersister();
try {
session.getEventListenerManager().dirtyCalculationStart();
// object loaded by update()
- final EntityEntry entry = event.getEntityEntry();
- final EntityPersister persister = entry.getPersister();
final Object[] values = event.getPropertyValues();
final Object[] loadedState = entry.getLoadedState();
final Object entity = event.getEntity();
@@ -532,6 +535,7 @@ public class DefaultFlushEntityEventListener implements FlushEntityEventListener
event.setDirtyCheckPossible( dirtyCheckPossible );
}
finally {
+ JfrEventManager.completeDirtyCalculationEvent( dirtyCalculationEvent, session, persister, entry, dirtyProperties );
session.getEventListenerManager().dirtyCalculationEnd( dirtyProperties != null );
}
return dirtyProperties;
diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultFlushEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultFlushEventListener.java
index 41d3ddb74e..5f4ac610ab 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultFlushEventListener.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultFlushEventListener.java
@@ -8,6 +8,7 @@ package org.hibernate.event.internal;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.PersistenceContext;
+import org.hibernate.event.jfr.internal.JfrEventManager;
import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.FlushEvent;
import org.hibernate.event.spi.FlushEventListener;
@@ -28,10 +29,9 @@ public class DefaultFlushEventListener extends AbstractFlushingEventListener imp
public void onFlush(FlushEvent event) throws HibernateException {
final EventSource source = event.getSession();
final PersistenceContext persistenceContext = source.getPersistenceContextInternal();
-
if ( persistenceContext.getNumberOfManagedEntities() > 0
|| persistenceContext.getCollectionEntriesSize() > 0 ) {
-
+ final org.hibernate.event.jfr.FlushEvent jfrFlushEvent = JfrEventManager.beginFlushEvent();
try {
source.getEventListenerManager().flushStart();
@@ -40,6 +40,7 @@ public class DefaultFlushEventListener extends AbstractFlushingEventListener imp
postFlush( source );
}
finally {
+ JfrEventManager.completeFlushEvent( jfrFlushEvent, event );
source.getEventListenerManager().flushEnd(
event.getNumberOfEntitiesProcessed(),
event.getNumberOfCollectionsProcessed()
diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultInitializeCollectionEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultInitializeCollectionEventListener.java
index f51aad0b8c..c3f9e1c182 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultInitializeCollectionEventListener.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultInitializeCollectionEventListener.java
@@ -127,7 +127,7 @@ public class DefaultInitializeCollectionEventListener implements InitializeColle
final SessionFactoryImplementor factory = source.getFactory();
final CollectionDataAccess cacheAccessStrategy = persister.getCacheAccessStrategy();
final Object ck = cacheAccessStrategy.generateCacheKey( id, persister, factory, source.getTenantIdentifier() );
- final Object ce = CacheHelper.fromSharedCache( source, ck, cacheAccessStrategy );
+ final Object ce = CacheHelper.fromSharedCache( source, ck, persister, cacheAccessStrategy );
final StatisticsImplementor statistics = factory.getStatistics();
if ( statistics.isStatisticsEnabled() ) {
diff --git a/hibernate-core/src/main/java/org/hibernate/event/jfr/CacheGetEvent.java b/hibernate-core/src/main/java/org/hibernate/event/jfr/CacheGetEvent.java
new file mode 100644
index 0000000000..295eac52f9
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/event/jfr/CacheGetEvent.java
@@ -0,0 +1,55 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
+ * See the lgpl.txt file in the root directory or .
+ */
+package org.hibernate.event.jfr;
+
+import org.hibernate.internal.build.AllowNonPortable;
+
+import jdk.jfr.Category;
+import jdk.jfr.Description;
+import jdk.jfr.Event;
+import jdk.jfr.Label;
+import jdk.jfr.Name;
+import jdk.jfr.StackTrace;
+
+@Name( CacheGetEvent.NAME )
+@Label( "Cache Get Executed" )
+@Category( "Hibernate ORM" )
+@Description( "Cache Get Executed" )
+@StackTrace(false)
+@AllowNonPortable
+public class CacheGetEvent extends Event {
+ public static final String NAME = "org.hibernate.orm.CacheGet";
+
+ @Label( "Session Identifier" )
+ public String sessionIdentifier;
+
+ @Label( "Entity Name" )
+ public String entityName;
+
+ @Label( "Collection Name" )
+ public String collectionName;
+
+ @Label( "Used Natural Id" )
+ public boolean isNaturalId;
+
+ @Label( "Region Name" )
+ public String regionName;
+
+ @Label( "Cache Get Execution Time" )
+ public long executionTime;
+
+ @Label("Cache Hit")
+ public boolean hit;
+
+ @Override
+ public String toString() {
+ return NAME ;
+ }
+
+ public transient long startedAt;
+
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/event/jfr/CachePutEvent.java b/hibernate-core/src/main/java/org/hibernate/event/jfr/CachePutEvent.java
new file mode 100644
index 0000000000..fac07b585b
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/event/jfr/CachePutEvent.java
@@ -0,0 +1,58 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
+ * See the lgpl.txt file in the root directory or .
+ */
+package org.hibernate.event.jfr;
+
+import org.hibernate.internal.build.AllowNonPortable;
+
+import jdk.jfr.Category;
+import jdk.jfr.Description;
+import jdk.jfr.Event;
+import jdk.jfr.Label;
+import jdk.jfr.Name;
+import jdk.jfr.StackTrace;
+
+@Name( CachePutEvent.NAME )
+@Label( "Cache Put Executed" )
+@Category( "Hibernate ORM" )
+@Description( "Cache Put Executed" )
+@StackTrace(false)
+@AllowNonPortable
+public class CachePutEvent extends Event {
+ public static final String NAME = "org.hibernate.orm.CachePut";
+
+ @Label( "Session Identifier" )
+ public String sessionIdentifier;
+
+ @Label( "Region Name" )
+ public String regionName;
+
+ @Label( "Entity Name" )
+ public String entityName;
+
+ @Label( "Collection Name" )
+ public String collectionName;
+
+ @Label( "Used Natural Id" )
+ public boolean isNaturalId;
+
+ @Label( "Cache Put Execution Time" )
+ public long executionTime;
+
+ @Label( "Description" )
+ public String description;
+
+ @Label( "Cache Content Has Changed" )
+ public boolean cacheChanged;
+
+ @Override
+ public String toString() {
+ return NAME ;
+ }
+
+ public transient long startedAt;
+
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/event/jfr/DirtyCalculationEvent.java b/hibernate-core/src/main/java/org/hibernate/event/jfr/DirtyCalculationEvent.java
new file mode 100644
index 0000000000..497f4d096e
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/event/jfr/DirtyCalculationEvent.java
@@ -0,0 +1,48 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
+ * See the lgpl.txt file in the root directory or .
+ */
+package org.hibernate.event.jfr;
+
+import org.hibernate.internal.build.AllowNonPortable;
+
+import jdk.jfr.Category;
+import jdk.jfr.Description;
+import jdk.jfr.Event;
+import jdk.jfr.Label;
+import jdk.jfr.Name;
+import jdk.jfr.StackTrace;
+
+@Name( DirtyCalculationEvent.NAME )
+@Label( "DirtyCalculationEvent Execution" )
+@Category( "Hibernate ORM" )
+@Description( "DirtyCalculationEvent Execution" )
+@StackTrace(false)
+@AllowNonPortable
+public class DirtyCalculationEvent extends Event {
+ public static final String NAME = "org.hibernate.orm.DirtyCalculationEvent";
+
+ @Label( "Session Identifier" )
+ public String sessionIdentifier;
+
+ @Label( "PartialFlushEvent time" )
+ public long executionTime;
+
+ @Label( "Entity Name" )
+ public String entityName;
+
+ @Label( "Entity Status" )
+ public String entityStatus;
+
+ @Label( "Found properties" )
+ public boolean dirty;
+
+ @Override
+ public String toString() {
+ return NAME ;
+ }
+
+ public transient long startedAt;
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/event/jfr/FlushEvent.java b/hibernate-core/src/main/java/org/hibernate/event/jfr/FlushEvent.java
new file mode 100644
index 0000000000..c1718679d9
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/event/jfr/FlushEvent.java
@@ -0,0 +1,49 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
+ * See the lgpl.txt file in the root directory or .
+ */
+package org.hibernate.event.jfr;
+
+import org.hibernate.internal.build.AllowNonPortable;
+
+import jdk.jfr.Category;
+import jdk.jfr.Description;
+import jdk.jfr.Event;
+import jdk.jfr.Label;
+import jdk.jfr.Name;
+import jdk.jfr.StackTrace;
+
+@Name( FlushEvent.NAME )
+@Label( "Flush Execution" )
+@Category( "Hibernate ORM" )
+@Description( "Flush Execution" )
+@StackTrace(false)
+@AllowNonPortable
+public class FlushEvent extends Event {
+ public static final String NAME = "org.hibernate.orm.FlushEvent";
+
+ @Label( "Session Identifier" )
+ public String sessionIdentifier;
+
+ @Label( "Number Of Processed Entities" )
+ public int numberOfEntitiesProcessed;
+
+ @Label( "Number Of Processed Collectionc" )
+ public int numberOfCollectionsProcessed;
+
+ @Label( "Flush time" )
+ public long executionTime;
+
+ @Label( "Auto Flush" )
+ public boolean isAutoFlush;
+
+ @Override
+ public String toString() {
+ return NAME ;
+ }
+
+ public transient long startedAt;
+
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/event/jfr/JdbcBatchExecutionEvent.java b/hibernate-core/src/main/java/org/hibernate/event/jfr/JdbcBatchExecutionEvent.java
new file mode 100644
index 0000000000..64f990b260
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/event/jfr/JdbcBatchExecutionEvent.java
@@ -0,0 +1,41 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
+ * See the lgpl.txt file in the root directory or .
+ */
+package org.hibernate.event.jfr;
+
+import org.hibernate.internal.build.AllowNonPortable;
+
+import jdk.jfr.Category;
+import jdk.jfr.Description;
+import jdk.jfr.Event;
+import jdk.jfr.Label;
+import jdk.jfr.Name;
+import jdk.jfr.StackTrace;
+
+@Name( JdbcBatchExecutionEvent.NAME )
+@Label( "JDBC Batch Execution" )
+@Category( "Hibernate ORM" )
+@Description( "JDBC Batch Execution" )
+@StackTrace(false)
+@AllowNonPortable
+public class JdbcBatchExecutionEvent extends Event {
+ public static final String NAME = "org.hibernate.orm.JdbcBatchExecution";
+
+ @Label("PreparedStatement SQL")
+ public String sql;
+
+ @Label( "Batch Execution time" )
+ public long executionTime;
+
+ @Override
+ public String toString() {
+ return NAME ;
+ }
+
+ public transient long startedAt;
+
+
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/event/jfr/JdbcConnectionAcquisitionEvent.java b/hibernate-core/src/main/java/org/hibernate/event/jfr/JdbcConnectionAcquisitionEvent.java
new file mode 100644
index 0000000000..fee14bc8c0
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/event/jfr/JdbcConnectionAcquisitionEvent.java
@@ -0,0 +1,42 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
+ * See the lgpl.txt file in the root directory or .
+ */
+package org.hibernate.event.jfr;
+
+import org.hibernate.internal.build.AllowNonPortable;
+
+import jdk.jfr.Category;
+import jdk.jfr.Description;
+import jdk.jfr.Event;
+import jdk.jfr.Label;
+import jdk.jfr.Name;
+import jdk.jfr.StackTrace;
+
+@Name(JdbcConnectionAcquisitionEvent.NAME )
+@Label( "JDBC Connection Obtained" )
+@Category( "Hibernate ORM" )
+@Description( "JDBC Connection Obtained" )
+@StackTrace(false)
+@AllowNonPortable
+public class JdbcConnectionAcquisitionEvent extends Event {
+ public static final String NAME = "org.hibernate.orm.JdbcConnectionAcquisition";
+
+ @Label("Session Identifier" )
+ public String sessionIdentifier;
+
+ @Label( "Tenant Identifier" )
+ public String tenantIdentifier;
+
+ @Label( "Connection Acquisition Time" )
+ public long executionTime;
+
+ @Override
+ public String toString() {
+ return NAME ;
+ }
+
+ public transient long startedAt;
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/event/jfr/JdbcConnectionReleaseEvent.java b/hibernate-core/src/main/java/org/hibernate/event/jfr/JdbcConnectionReleaseEvent.java
new file mode 100644
index 0000000000..ee7b46b6db
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/event/jfr/JdbcConnectionReleaseEvent.java
@@ -0,0 +1,43 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
+ * See the lgpl.txt file in the root directory or .
+ */
+package org.hibernate.event.jfr;
+
+import org.hibernate.internal.build.AllowNonPortable;
+
+import jdk.jfr.Category;
+import jdk.jfr.Description;
+import jdk.jfr.Event;
+import jdk.jfr.Label;
+import jdk.jfr.Name;
+import jdk.jfr.StackTrace;
+
+@Name(JdbcConnectionReleaseEvent.NAME )
+@Label( "JDBC Connection Release" )
+@Category( "Hibernate ORM" )
+@Description( "JDBC Connection Released" )
+@StackTrace(false)
+@AllowNonPortable
+public class JdbcConnectionReleaseEvent extends Event {
+ public static final String NAME = "org.hibernate.orm.JdbcConnectionRelease";
+
+ @Label("Session Identifier" )
+ public String sessionIdentifier;
+
+ @Label( "Tenant Identifier" )
+ public String tenantIdentifier;
+
+ @Label( "Connection Release Time" )
+ public long executionTime;
+
+ @Override
+ public String toString() {
+ return NAME ;
+ }
+
+ public transient long startedAt;
+
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/event/jfr/JdbcPreparedStatementCreationEvent.java b/hibernate-core/src/main/java/org/hibernate/event/jfr/JdbcPreparedStatementCreationEvent.java
new file mode 100644
index 0000000000..18a14f4ad3
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/event/jfr/JdbcPreparedStatementCreationEvent.java
@@ -0,0 +1,40 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
+ * See the lgpl.txt file in the root directory or .
+ */
+package org.hibernate.event.jfr;
+
+import org.hibernate.internal.build.AllowNonPortable;
+
+import jdk.jfr.Category;
+import jdk.jfr.Description;
+import jdk.jfr.Event;
+import jdk.jfr.Label;
+import jdk.jfr.Name;
+import jdk.jfr.StackTrace;
+
+@Name(JdbcPreparedStatementCreationEvent.NAME)
+@Label("JDBC PreparedStatement Created")
+@Category("Hibernate ORM")
+@Description("JDBC PreparedStatement Created")
+@StackTrace(false)
+@AllowNonPortable
+public class JdbcPreparedStatementCreationEvent extends Event {
+ public static final String NAME = "org.hibernate.orm.JdbcPreparedStatementCreation";
+
+ @Label("PreparedStatement SQL")
+ public String sql;
+
+ @Label("PreparedStatement Creation Time")
+ public long executionTime;
+
+ @Override
+ public String toString() {
+ return NAME;
+ }
+
+ public transient long startedAt;
+
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/event/jfr/JdbcPreparedStatementExecutionEvent.java b/hibernate-core/src/main/java/org/hibernate/event/jfr/JdbcPreparedStatementExecutionEvent.java
new file mode 100644
index 0000000000..4ceab9cef6
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/event/jfr/JdbcPreparedStatementExecutionEvent.java
@@ -0,0 +1,40 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
+ * See the lgpl.txt file in the root directory or .
+ */
+package org.hibernate.event.jfr;
+
+import org.hibernate.internal.build.AllowNonPortable;
+
+import jdk.jfr.Category;
+import jdk.jfr.Description;
+import jdk.jfr.Event;
+import jdk.jfr.Label;
+import jdk.jfr.Name;
+import jdk.jfr.StackTrace;
+
+@Name(JdbcPreparedStatementExecutionEvent.NAME )
+@Label( "JDBC PreparedStatement Executed" )
+@Category( "Hibernate ORM" )
+@Description( "JDBC PreparedStatement Executed" )
+@StackTrace(false)
+@AllowNonPortable
+public class JdbcPreparedStatementExecutionEvent extends Event {
+ public static final String NAME = "org.hibernate.orm.JdbcPreparedStatementExecution";
+
+ @Label( "PreparedStatement SQL" )
+ public String sql;
+
+ @Label( "PreparedStatement Execution Time" )
+ public long executionTime;
+
+ @Override
+ public String toString() {
+ return NAME ;
+ }
+
+ public transient long startedAt;
+
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/event/jfr/PartialFlushEvent.java b/hibernate-core/src/main/java/org/hibernate/event/jfr/PartialFlushEvent.java
new file mode 100644
index 0000000000..d94f54c754
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/event/jfr/PartialFlushEvent.java
@@ -0,0 +1,49 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
+ * See the lgpl.txt file in the root directory or .
+ */
+package org.hibernate.event.jfr;
+
+import org.hibernate.internal.build.AllowNonPortable;
+
+import jdk.jfr.Category;
+import jdk.jfr.Description;
+import jdk.jfr.Event;
+import jdk.jfr.Label;
+import jdk.jfr.Name;
+import jdk.jfr.StackTrace;
+
+@Name( PartialFlushEvent.NAME )
+@Label( "PartialFlushEvent Execution" )
+@Category( "Hibernate ORM" )
+@Description( "PartialFlushEvent Execution" )
+@StackTrace(false)
+@AllowNonPortable
+public class PartialFlushEvent extends Event {
+ public static final String NAME = "org.hibernate.orm.PartialFlushEvent";
+
+ @Label( "Session Identifier" )
+ public String sessionIdentifier;
+
+ @Label( "Number Of Processed Entities" )
+ public int numberOfEntitiesProcessed;
+
+ @Label( "Number Of Processed Collectionc" )
+ public int numberOfCollectionsProcessed;
+
+ @Label( "PartialFlushEvent time" )
+ public long executionTime;
+
+ @Label( "Auto Flush" )
+ public boolean isAutoFlush;
+
+ @Override
+ public String toString() {
+ return NAME ;
+ }
+
+ public transient long startedAt;
+
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/event/jfr/SessionOpenEvent.java b/hibernate-core/src/main/java/org/hibernate/event/jfr/SessionOpenEvent.java
index 379603ecaf..fd2cbe19a4 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/jfr/SessionOpenEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/jfr/SessionOpenEvent.java
@@ -25,7 +25,7 @@ import jdk.jfr.StackTrace;
@StackTrace(false)
@AllowNonPortable
public class SessionOpenEvent extends Event {
- public static final String NAME = "org.hibernate.orm.SessionOpened";
+ public static final String NAME = "org.hibernate.orm.SessionOpen";
@Label("Session Identifier" )
public String sessionIdentifier;
diff --git a/hibernate-core/src/main/java/org/hibernate/event/jfr/internal/JfrEventManager.java b/hibernate-core/src/main/java/org/hibernate/event/jfr/internal/JfrEventManager.java
new file mode 100644
index 0000000000..4c4c0bc818
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/event/jfr/internal/JfrEventManager.java
@@ -0,0 +1,479 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
+ * See the lgpl.txt file in the root directory or .
+ */
+package org.hibernate.event.jfr.internal;
+
+import java.sql.PreparedStatement;
+
+import org.hibernate.cache.spi.Region;
+import org.hibernate.cache.spi.access.CachedDomainDataAccess;
+import org.hibernate.engine.spi.EntityEntry;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
+import org.hibernate.event.jfr.CacheGetEvent;
+import org.hibernate.event.jfr.CachePutEvent;
+import org.hibernate.event.jfr.DirtyCalculationEvent;
+import org.hibernate.event.jfr.FlushEvent;
+import org.hibernate.event.jfr.JdbcBatchExecutionEvent;
+import org.hibernate.event.jfr.JdbcConnectionAcquisitionEvent;
+import org.hibernate.event.jfr.JdbcConnectionReleaseEvent;
+import org.hibernate.event.jfr.JdbcPreparedStatementCreationEvent;
+import org.hibernate.event.jfr.JdbcPreparedStatementExecutionEvent;
+import org.hibernate.event.jfr.PartialFlushEvent;
+import org.hibernate.event.jfr.SessionClosedEvent;
+import org.hibernate.event.jfr.SessionOpenEvent;
+import org.hibernate.event.spi.AutoFlushEvent;
+import org.hibernate.event.spi.EventSource;
+import org.hibernate.internal.build.AllowNonPortable;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.stat.internal.StatsHelper;
+
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+@AllowNonPortable
+public class JfrEventManager {
+
+ public static SessionOpenEvent beginSessionOpenEvent() {
+ final SessionOpenEvent sessionOpenEvent = new SessionOpenEvent();
+ if ( sessionOpenEvent.isEnabled() ) {
+ sessionOpenEvent.begin();
+ }
+ return sessionOpenEvent;
+ }
+
+ public static void completeSessionOpenEvent(
+ SessionOpenEvent sessionOpenEvent,
+ SharedSessionContractImplementor session) {
+ if ( sessionOpenEvent.isEnabled() ) {
+ sessionOpenEvent.end();
+ if ( sessionOpenEvent.shouldCommit() ) {
+ sessionOpenEvent.sessionIdentifier = getSessionIdentifier( session );
+ sessionOpenEvent.commit();
+ }
+ }
+ }
+
+ public static SessionClosedEvent beginSessionClosedEvent() {
+ final SessionClosedEvent sessionClosedEvent = new SessionClosedEvent();
+ if ( sessionClosedEvent.isEnabled() ) {
+ sessionClosedEvent.begin();
+ }
+ return sessionClosedEvent;
+ }
+
+ public static void completeSessionClosedEvent(
+ SessionClosedEvent sessionClosedEvent,
+ SharedSessionContractImplementor session) {
+ if ( sessionClosedEvent.isEnabled() ) {
+ sessionClosedEvent.end();
+ if ( sessionClosedEvent.shouldCommit() ) {
+ sessionClosedEvent.sessionIdentifier = getSessionIdentifier( session );
+ sessionClosedEvent.commit();
+ }
+ }
+ }
+
+ public static JdbcConnectionAcquisitionEvent beginJdbcConnectionAcquisitionEvent() {
+ final JdbcConnectionAcquisitionEvent jdbcConnectionAcquisitionEvent = new JdbcConnectionAcquisitionEvent();
+ if ( jdbcConnectionAcquisitionEvent.isEnabled() ) {
+ jdbcConnectionAcquisitionEvent.begin();
+ jdbcConnectionAcquisitionEvent.startedAt = System.nanoTime();
+ }
+ return jdbcConnectionAcquisitionEvent;
+ }
+
+ public static void completeJdbcConnectionAcquisitionEvent(
+ JdbcConnectionAcquisitionEvent jdbcConnectionAcquisitionEvent,
+ SharedSessionContractImplementor session,
+ String tenantId) {
+ if ( jdbcConnectionAcquisitionEvent.isEnabled() ) {
+ jdbcConnectionAcquisitionEvent.end();
+ if ( jdbcConnectionAcquisitionEvent.shouldCommit() ) {
+ jdbcConnectionAcquisitionEvent.executionTime = getExecutionTime( jdbcConnectionAcquisitionEvent.startedAt );
+ jdbcConnectionAcquisitionEvent.sessionIdentifier = getSessionIdentifier( session );
+ jdbcConnectionAcquisitionEvent.tenantIdentifier = tenantId;
+ jdbcConnectionAcquisitionEvent.commit();
+ }
+ }
+ }
+
+ public static JdbcConnectionReleaseEvent beginJdbcConnectionReleaseEvent() {
+ final JdbcConnectionReleaseEvent jdbcConnectionReleaseEvent = new JdbcConnectionReleaseEvent();
+ if ( jdbcConnectionReleaseEvent.isEnabled() ) {
+ jdbcConnectionReleaseEvent.begin();
+ jdbcConnectionReleaseEvent.startedAt = System.nanoTime();
+ }
+ return jdbcConnectionReleaseEvent;
+ }
+
+ public static void completeJdbcConnectionReleaseEvent(
+ JdbcConnectionReleaseEvent jdbcConnectionReleaseEvent,
+ SharedSessionContractImplementor session,
+ String tenantId) {
+ if ( jdbcConnectionReleaseEvent.isEnabled() ) {
+ jdbcConnectionReleaseEvent.end();
+ if ( jdbcConnectionReleaseEvent.shouldCommit() ) {
+ jdbcConnectionReleaseEvent.executionTime = getExecutionTime( jdbcConnectionReleaseEvent.startedAt );
+ jdbcConnectionReleaseEvent.sessionIdentifier = getSessionIdentifier( session );
+ jdbcConnectionReleaseEvent.tenantIdentifier = tenantId;
+ jdbcConnectionReleaseEvent.commit();
+ }
+ }
+ }
+
+ public static JdbcPreparedStatementCreationEvent beginJdbcPreparedStatementCreationEvent() {
+ final JdbcPreparedStatementCreationEvent jdbcPreparedStatementCreation = new JdbcPreparedStatementCreationEvent();
+ if ( jdbcPreparedStatementCreation.isEnabled() ) {
+ jdbcPreparedStatementCreation.begin();
+ jdbcPreparedStatementCreation.startedAt = System.nanoTime();
+ }
+ return jdbcPreparedStatementCreation;
+ }
+
+ public static void completeJdbcPreparedStatementCreationEvent(
+ JdbcPreparedStatementCreationEvent jdbcPreparedStatementCreation,
+ String preparedStatementSql) {
+ if ( jdbcPreparedStatementCreation.isEnabled() ) {
+ jdbcPreparedStatementCreation.end();
+ if ( jdbcPreparedStatementCreation.shouldCommit() ) {
+ jdbcPreparedStatementCreation.executionTime = getExecutionTime( jdbcPreparedStatementCreation.startedAt );
+ jdbcPreparedStatementCreation.sql = preparedStatementSql;
+ jdbcPreparedStatementCreation.commit();
+ }
+ }
+ }
+
+ public static JdbcPreparedStatementExecutionEvent beginJdbcPreparedStatementExecutionEvent() {
+ final JdbcPreparedStatementExecutionEvent jdbcPreparedStatementExecutionEvent = new JdbcPreparedStatementExecutionEvent();
+ if ( jdbcPreparedStatementExecutionEvent.isEnabled() ) {
+ jdbcPreparedStatementExecutionEvent.begin();
+ jdbcPreparedStatementExecutionEvent.startedAt = System.nanoTime();
+ }
+ return jdbcPreparedStatementExecutionEvent;
+ }
+
+ public static void completeJdbcPreparedStatementExecutionEvent(
+ JdbcPreparedStatementExecutionEvent jdbcPreparedStatementExecutionEvent,
+ String preparedStatementSql) {
+ if ( jdbcPreparedStatementExecutionEvent.isEnabled() ) {
+ jdbcPreparedStatementExecutionEvent.end();
+ if ( jdbcPreparedStatementExecutionEvent.shouldCommit() ) {
+ jdbcPreparedStatementExecutionEvent.executionTime = getExecutionTime(
+ jdbcPreparedStatementExecutionEvent.startedAt );
+ jdbcPreparedStatementExecutionEvent.sql = preparedStatementSql;
+ jdbcPreparedStatementExecutionEvent.commit();
+ }
+ }
+ }
+
+ public static JdbcBatchExecutionEvent beginJdbcBatchExecutionEvent() {
+ final JdbcBatchExecutionEvent jdbcBatchExecutionEvent = new JdbcBatchExecutionEvent();
+ if ( jdbcBatchExecutionEvent.isEnabled() ) {
+ jdbcBatchExecutionEvent.begin();
+ jdbcBatchExecutionEvent.startedAt = System.nanoTime();
+ }
+ return jdbcBatchExecutionEvent;
+ }
+
+ public static void completeJdbcBatchExecutionEvent(
+ JdbcBatchExecutionEvent jdbcBatchExecutionEvent,
+ String statementSql) {
+ if ( jdbcBatchExecutionEvent.isEnabled() ) {
+ jdbcBatchExecutionEvent.end();
+ if ( jdbcBatchExecutionEvent.shouldCommit() ) {
+ jdbcBatchExecutionEvent.executionTime = getExecutionTime( jdbcBatchExecutionEvent.startedAt );
+ jdbcBatchExecutionEvent.sql = statementSql;
+ jdbcBatchExecutionEvent.commit();
+ }
+ }
+ }
+
+ public static CachePutEvent beginCachePutEvent() {
+ final CachePutEvent cachePutEvent = new CachePutEvent();
+ if ( cachePutEvent.isEnabled() ) {
+ cachePutEvent.begin();
+ cachePutEvent.startedAt = System.nanoTime();
+ }
+ return cachePutEvent;
+ }
+
+ public static void completeCachePutEvent(
+ CachePutEvent cachePutEvent,
+ SharedSessionContractImplementor session,
+ Region region,
+ boolean cacheContentChanged,
+ CacheActionDescription description) {
+ if ( cachePutEvent.isEnabled() ) {
+ cachePutEvent.end();
+ if ( cachePutEvent.shouldCommit() ) {
+ cachePutEvent.executionTime = getExecutionTime( cachePutEvent.startedAt );
+ cachePutEvent.sessionIdentifier = getSessionIdentifier( session );
+ cachePutEvent.regionName = region.getName();
+ cachePutEvent.description = description.getText();
+ cachePutEvent.cacheChanged = cacheContentChanged;
+ cachePutEvent.commit();
+ }
+ }
+ }
+
+ public static void completeCachePutEvent(
+ CachePutEvent cachePutEvent,
+ SharedSessionContractImplementor session,
+ CachedDomainDataAccess cachedDomainDataAccess,
+ EntityPersister persister,
+ boolean cacheContentChanged,
+ CacheActionDescription description) {
+ completeCachePutEvent(
+ cachePutEvent,
+ session,
+ cachedDomainDataAccess,
+ persister,
+ cacheContentChanged,
+ false,
+ description
+ );
+ }
+
+ public static void completeCachePutEvent(
+ CachePutEvent cachePutEvent,
+ SharedSessionContractImplementor session,
+ CachedDomainDataAccess cachedDomainDataAccess,
+ EntityPersister persister,
+ boolean cacheContentChanged,
+ boolean isNatualId,
+ CacheActionDescription description) {
+ if ( cachePutEvent.isEnabled() ) {
+ cachePutEvent.end();
+ if ( cachePutEvent.shouldCommit() ) {
+ cachePutEvent.executionTime = getExecutionTime( cachePutEvent.startedAt );
+ cachePutEvent.sessionIdentifier = getSessionIdentifier( session );
+ cachePutEvent.regionName = cachedDomainDataAccess.getRegion().getName();
+ cachePutEvent.entityName = getEntityName( persister );
+ cachePutEvent.description = description.getText();
+ cachePutEvent.isNaturalId = isNatualId;
+ cachePutEvent.cacheChanged = cacheContentChanged;
+ cachePutEvent.commit();
+ }
+ }
+ }
+
+ public static void completeCachePutEvent(
+ CachePutEvent cachePutEvent,
+ SharedSessionContractImplementor session,
+ CachedDomainDataAccess cachedDomainDataAccess,
+ CollectionPersister persister,
+ boolean cacheContentChanged,
+ CacheActionDescription description) {
+ if ( cachePutEvent.isEnabled() ) {
+ cachePutEvent.end();
+ if ( cachePutEvent.shouldCommit() ) {
+ cachePutEvent.executionTime = getExecutionTime( cachePutEvent.startedAt );
+ cachePutEvent.sessionIdentifier = getSessionIdentifier( session );
+ cachePutEvent.regionName = cachedDomainDataAccess.getRegion().getName();
+ cachePutEvent.collectionName = persister.getNavigableRole().getFullPath();
+ cachePutEvent.description = description.getText();
+ cachePutEvent.cacheChanged = cacheContentChanged;
+ cachePutEvent.commit();
+ }
+ }
+ }
+
+ public static CacheGetEvent beginCacheGetEvent() {
+ final CacheGetEvent cacheGetEvent = new CacheGetEvent();
+ if ( cacheGetEvent.isEnabled() ) {
+ cacheGetEvent.begin();
+ cacheGetEvent.startedAt = System.nanoTime();
+ }
+ return cacheGetEvent;
+ }
+
+ public static void completeCacheGetEvent(
+ CacheGetEvent cacheGetEvent,
+ SharedSessionContractImplementor session,
+ Region region,
+ boolean hit) {
+ if ( cacheGetEvent.isEnabled() ) {
+ cacheGetEvent.end();
+ if ( cacheGetEvent.shouldCommit() ) {
+ cacheGetEvent.executionTime = getExecutionTime( cacheGetEvent.startedAt );
+ cacheGetEvent.sessionIdentifier = getSessionIdentifier( session );
+ cacheGetEvent.regionName = region.getName();
+ cacheGetEvent.hit = hit;
+ cacheGetEvent.commit();
+ }
+ }
+ }
+
+ public static void completeCacheGetEvent(
+ CacheGetEvent cacheGetEvent,
+ SharedSessionContractImplementor session,
+ Region region,
+ EntityPersister persister,
+ boolean isNaturalKey,
+ boolean hit) {
+ if ( cacheGetEvent.isEnabled() ) {
+ cacheGetEvent.end();
+ if ( cacheGetEvent.shouldCommit() ) {
+ cacheGetEvent.executionTime = getExecutionTime( cacheGetEvent.startedAt );
+ cacheGetEvent.sessionIdentifier = getSessionIdentifier( session );
+ cacheGetEvent.entityName = getEntityName( persister );
+ cacheGetEvent.regionName = region.getName();
+ cacheGetEvent.isNaturalId = isNaturalKey;
+ cacheGetEvent.hit = hit;
+ cacheGetEvent.commit();
+ }
+ }
+ }
+
+ public static void completeCacheGetEvent(
+ CacheGetEvent cacheGetEvent,
+ SharedSessionContractImplementor session,
+ Region region,
+ CollectionPersister persister,
+ boolean hit) {
+ if ( cacheGetEvent.isEnabled() ) {
+ cacheGetEvent.end();
+ if ( cacheGetEvent.shouldCommit() ) {
+ cacheGetEvent.executionTime = getExecutionTime( cacheGetEvent.startedAt );
+ cacheGetEvent.sessionIdentifier = getSessionIdentifier( session );
+ cacheGetEvent.collectionName = persister.getNavigableRole().getFullPath();
+ cacheGetEvent.regionName = region.getName();
+ cacheGetEvent.hit = hit;
+ cacheGetEvent.commit();
+ }
+ }
+ }
+
+ public static FlushEvent beginFlushEvent() {
+ final FlushEvent flushEvent = new FlushEvent();
+ if ( flushEvent.isEnabled() ) {
+ flushEvent.begin();
+ flushEvent.startedAt = System.nanoTime();
+ }
+ return flushEvent;
+ }
+
+ public static void completeFlushEvent(
+ FlushEvent flushEvent,
+ org.hibernate.event.spi.FlushEvent event) {
+ completeFlushEvent( flushEvent, event, false );
+ }
+
+ public static void completeFlushEvent(
+ FlushEvent flushEvent,
+ org.hibernate.event.spi.FlushEvent event,
+ boolean autoFlush) {
+ if ( flushEvent.isEnabled() ) {
+ flushEvent.end();
+ if ( flushEvent.shouldCommit() ) {
+ flushEvent.executionTime = getExecutionTime( flushEvent.startedAt );
+ EventSource session = event.getSession();
+ flushEvent.sessionIdentifier = getSessionIdentifier( session );
+ flushEvent.numberOfEntitiesProcessed = event.getNumberOfEntitiesProcessed();
+ flushEvent.numberOfCollectionsProcessed = event.getNumberOfCollectionsProcessed();
+ flushEvent.isAutoFlush = autoFlush;
+ flushEvent.commit();
+ }
+ }
+ }
+
+ public static PartialFlushEvent beginPartialFlushEvent() {
+ final PartialFlushEvent partialFlushEvent = new PartialFlushEvent();
+ if ( partialFlushEvent.isEnabled() ) {
+ partialFlushEvent.startedAt = System.nanoTime();
+ partialFlushEvent.begin();
+ }
+ return partialFlushEvent;
+ }
+
+ public static void completePartialFlushEvent(
+ PartialFlushEvent flushEvent,
+ AutoFlushEvent event) {
+ if ( flushEvent.isEnabled() ) {
+ flushEvent.end();
+ if ( flushEvent.shouldCommit() ) {
+ flushEvent.executionTime = getExecutionTime( flushEvent.startedAt );
+ EventSource session = event.getSession();
+ flushEvent.sessionIdentifier = getSessionIdentifier( session );
+ flushEvent.numberOfEntitiesProcessed = event.getNumberOfEntitiesProcessed();
+ flushEvent.numberOfCollectionsProcessed = event.getNumberOfCollectionsProcessed();
+ flushEvent.isAutoFlush = true;
+ flushEvent.commit();
+ }
+ }
+ }
+
+ public static DirtyCalculationEvent beginDirtyCalculationEvent() {
+ final DirtyCalculationEvent dirtyCalculationEvent = new DirtyCalculationEvent();
+ if ( dirtyCalculationEvent.isEnabled() ) {
+ dirtyCalculationEvent.startedAt = System.nanoTime();
+ dirtyCalculationEvent.begin();
+ }
+ return dirtyCalculationEvent;
+ }
+
+ public static void completeDirtyCalculationEvent(
+ DirtyCalculationEvent dirtyCalculationEvent,
+ SharedSessionContractImplementor session,
+ EntityPersister persister,
+ EntityEntry entry,
+ int[] dirtyProperties) {
+ if ( dirtyCalculationEvent.isEnabled() ) {
+ dirtyCalculationEvent.end();
+ if ( dirtyCalculationEvent.shouldCommit() ) {
+ dirtyCalculationEvent.executionTime = getExecutionTime( dirtyCalculationEvent.startedAt );
+ dirtyCalculationEvent.sessionIdentifier = getSessionIdentifier( session );
+ dirtyCalculationEvent.entityName = getEntityName( persister );
+ dirtyCalculationEvent.entityStatus = entry.getStatus().name();
+ dirtyCalculationEvent.dirty = dirtyProperties != null;
+ dirtyCalculationEvent.commit();
+ }
+ }
+ }
+
+ public enum CacheActionDescription {
+ ENTITY_INSERT( "Entity Insert" ),
+ ENTITY_AFTER_INSERT( "Entity After Insert" ),
+ ENTITY_UPDATE( "Entity Update" ),
+ ENTITY_LOAD( "Entity Load" ),
+ ENTITY_AFTER_UPDATE( "Entity After Update" ),
+ TIMESTAMP_PRE_INVALIDATE( "Timestamp Pre Invalidate" ),
+ TIMESTAMP_INVALIDATE( "Timestamp Invalidate" ),
+ COLLECTION_INSERT( "Collection Insert" ),
+ QUERY_RESULT( "Query Result" );
+
+
+ private final String text;
+
+ CacheActionDescription(String text) {
+ this.text = text;
+ }
+
+ @Override
+ public String toString() {
+ return text;
+ }
+
+ public String getText() {
+ return text;
+ }
+ }
+
+ private static long getExecutionTime(Long startTime) {
+ return NANOSECONDS.convert( System.nanoTime() - startTime, NANOSECONDS );
+ }
+
+ private static String getSessionIdentifier(SharedSessionContractImplementor session) {
+ if ( session == null ) {
+ return null;
+ }
+ return session.getSessionIdentifier().toString();
+ }
+
+ private static String getEntityName(EntityPersister persister) {
+ return StatsHelper.INSTANCE.getRootEntityRole( persister ).getFullPath();
+ }
+}
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 8f9f9ee20b..996892f36e 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
@@ -34,6 +34,9 @@ import org.hibernate.engine.jdbc.internal.FormatStyle;
import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
import org.hibernate.engine.spi.SessionEventListenerManager;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
+import org.hibernate.event.jfr.JdbcPreparedStatementExecutionEvent;
+import org.hibernate.event.jfr.internal.JfrEventManager;
+import org.hibernate.event.jfr.JdbcPreparedStatementCreationEvent;
import org.hibernate.id.ExportableColumn;
import org.hibernate.id.IdentifierGeneratorHelper;
import org.hibernate.id.IntegralDataTypeHolder;
@@ -593,7 +596,7 @@ public class TableGenerator implements PersistentIdentifierGenerator {
try ( PreparedStatement selectPS = prepareStatement( connection, selectQuery, logger, listener ) ) {
selectPS.setString( 1, segmentValue );
- final ResultSet selectRS = executeQuery( selectPS, listener );
+ final ResultSet selectRS = executeQuery( selectPS, listener, selectQuery );
if ( !selectRS.next() ) {
long initializationValue;
if ( storeLastUsedValue ) {
@@ -608,7 +611,7 @@ public class TableGenerator implements PersistentIdentifierGenerator {
LOG.tracef( "binding parameter [%s] - [%s]", 1, segmentValue );
statement.setString( 1, segmentValue );
value.bind( statement, 2 );
- executeUpdate( statement, listener);
+ executeUpdate( statement, listener, insertQuery);
}
}
else {
@@ -640,7 +643,7 @@ public class TableGenerator implements PersistentIdentifierGenerator {
updateValue.bind( statement, 1 );
value.bind( statement, 2 );
statement.setString( 3, segmentValue );
- rows = executeUpdate( statement, listener );
+ rows = executeUpdate( statement, listener, updateQuery );
}
catch (SQLException e) {
LOG.unableToUpdateQueryHiValue( physicalTableName.render(), e );
@@ -664,32 +667,37 @@ public class TableGenerator implements PersistentIdentifierGenerator {
SqlStatementLogger logger,
SessionEventListenerManager listener) throws SQLException {
logger.logStatement( sql, FormatStyle.BASIC.getFormatter() );
+ final JdbcPreparedStatementCreationEvent jdbcPreparedStatementCreation = JfrEventManager.beginJdbcPreparedStatementCreationEvent();
try {
listener.jdbcPrepareStatementStart();
return connection.prepareStatement( sql );
}
finally {
+ JfrEventManager.completeJdbcPreparedStatementCreationEvent( jdbcPreparedStatementCreation, sql );
listener.jdbcPrepareStatementEnd();
}
}
- private int executeUpdate(PreparedStatement ps, SessionEventListenerManager listener) throws SQLException {
+ private int executeUpdate(PreparedStatement ps, SessionEventListenerManager listener, String sql ) throws SQLException {
+ final JdbcPreparedStatementExecutionEvent jdbcPreparedStatementExecutionEvent = JfrEventManager.beginJdbcPreparedStatementExecutionEvent();
try {
listener.jdbcExecuteStatementStart();
return ps.executeUpdate();
}
finally {
+ JfrEventManager.completeJdbcPreparedStatementExecutionEvent( jdbcPreparedStatementExecutionEvent, sql );
listener.jdbcExecuteStatementEnd();
}
-
}
- private ResultSet executeQuery(PreparedStatement ps, SessionEventListenerManager listener) throws SQLException {
+ private ResultSet executeQuery(PreparedStatement ps, SessionEventListenerManager listener, String sql ) throws SQLException {
+ final JdbcPreparedStatementExecutionEvent jdbcPreparedStatementExecutionEvent = JfrEventManager.beginJdbcPreparedStatementExecutionEvent();
try {
listener.jdbcExecuteStatementStart();
return ps.executeQuery();
}
finally {
+ JfrEventManager.completeJdbcPreparedStatementExecutionEvent( jdbcPreparedStatementExecutionEvent, sql );
listener.jdbcExecuteStatementEnd();
}
}
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 0d1527476c..42703c5dd6 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
@@ -26,6 +26,9 @@ import org.hibernate.engine.jdbc.internal.FormatStyle;
import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
import org.hibernate.engine.spi.SessionEventListenerManager;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
+import org.hibernate.event.jfr.JdbcPreparedStatementExecutionEvent;
+import org.hibernate.event.jfr.internal.JfrEventManager;
+import org.hibernate.event.jfr.JdbcPreparedStatementCreationEvent;
import org.hibernate.id.ExportableColumn;
import org.hibernate.id.IdentifierGenerationException;
import org.hibernate.id.IdentifierGeneratorHelper;
@@ -143,7 +146,7 @@ public class TableStructure implements DatabaseStructure {
statementLogger,
statsCollector
)) {
- final ResultSet selectRS = executeQuery( selectStatement, statsCollector );
+ final ResultSet selectRS = executeQuery( selectStatement, statsCollector, selectQuery );
if ( !selectRS.next() ) {
final String err = "could not read a hi value - you need to populate the table: " + physicalTableName;
LOG.error( err );
@@ -168,7 +171,7 @@ public class TableStructure implements DatabaseStructure {
final IntegralDataTypeHolder updateValue = value.copy().add( increment );
updateValue.bind( updatePS, 1 );
value.bind( updatePS, 2 );
- rows = executeUpdate( updatePS, statsCollector );
+ rows = executeUpdate( updatePS, statsCollector, updateQuery );
}
catch (SQLException e) {
LOG.unableToUpdateQueryHiValue( physicalTableName.render(), e );
@@ -198,32 +201,38 @@ public class TableStructure implements DatabaseStructure {
SqlStatementLogger statementLogger,
SessionEventListenerManager statsCollector) throws SQLException {
statementLogger.logStatement( sql, FormatStyle.BASIC.getFormatter() );
+ final JdbcPreparedStatementCreationEvent jdbcPreparedStatementCreation = JfrEventManager.beginJdbcPreparedStatementCreationEvent();
try {
statsCollector.jdbcPrepareStatementStart();
return connection.prepareStatement( sql );
}
finally {
+ JfrEventManager.completeJdbcPreparedStatementCreationEvent( jdbcPreparedStatementCreation, sql );
statsCollector.jdbcPrepareStatementEnd();
}
}
- private int executeUpdate(PreparedStatement ps, SessionEventListenerManager statsCollector) throws SQLException {
+ private int executeUpdate(PreparedStatement ps, SessionEventListenerManager statsCollector, String sql ) throws SQLException {
+ final JdbcPreparedStatementExecutionEvent jdbcPreparedStatementExecutionEvent = JfrEventManager.beginJdbcPreparedStatementExecutionEvent();
try {
statsCollector.jdbcExecuteStatementStart();
return ps.executeUpdate();
}
finally {
+ JfrEventManager.completeJdbcPreparedStatementExecutionEvent( jdbcPreparedStatementExecutionEvent, sql );
statsCollector.jdbcExecuteStatementEnd();
}
}
- private ResultSet executeQuery(PreparedStatement ps, SessionEventListenerManager statsCollector) throws SQLException {
+ private ResultSet executeQuery(PreparedStatement ps, SessionEventListenerManager statsCollector, String sql ) throws SQLException {
+ final JdbcPreparedStatementExecutionEvent jdbcPreparedStatementExecutionEvent = JfrEventManager.beginJdbcPreparedStatementExecutionEvent();
try {
statsCollector.jdbcExecuteStatementStart();
return ps.executeQuery();
}
finally {
+ JfrEventManager.completeJdbcPreparedStatementExecutionEvent( jdbcPreparedStatementExecutionEvent, sql );
statsCollector.jdbcExecuteStatementEnd();
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java
index 178b4cce37..b99765a935 100644
--- a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java
+++ b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java
@@ -602,14 +602,16 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
if ( ! fastSessionServices.requiresMultiTenantConnectionProvider ) {
jdbcConnectionAccess = new NonContextualJdbcConnectionAccess(
getEventListenerManager(),
- fastSessionServices.connectionProvider
+ fastSessionServices.connectionProvider,
+ this
);
}
else {
jdbcConnectionAccess = new ContextualJdbcConnectionAccess(
getTenantIdentifier(),
getEventListenerManager(),
- fastSessionServices.multiTenantConnectionProvider
+ fastSessionServices.multiTenantConnectionProvider,
+ this
);
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/internal/ContextualJdbcConnectionAccess.java b/hibernate-core/src/main/java/org/hibernate/internal/ContextualJdbcConnectionAccess.java
index 0219d70be1..2fa07fb74b 100644
--- a/hibernate-core/src/main/java/org/hibernate/internal/ContextualJdbcConnectionAccess.java
+++ b/hibernate-core/src/main/java/org/hibernate/internal/ContextualJdbcConnectionAccess.java
@@ -14,6 +14,10 @@ import org.hibernate.HibernateException;
import org.hibernate.SessionEventListener;
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
+import org.hibernate.event.jfr.internal.JfrEventManager;
+import org.hibernate.event.jfr.JdbcConnectionAcquisitionEvent;
+import org.hibernate.event.jfr.JdbcConnectionReleaseEvent;
/**
* @author Steve Ebersole
@@ -22,14 +26,18 @@ public class ContextualJdbcConnectionAccess implements JdbcConnectionAccess, Ser
private final String tenantIdentifier;
private final SessionEventListener listener;
private final MultiTenantConnectionProvider connectionProvider;
+ private final SharedSessionContractImplementor session;
+
public ContextualJdbcConnectionAccess(
String tenantIdentifier,
SessionEventListener listener,
- MultiTenantConnectionProvider connectionProvider) {
+ MultiTenantConnectionProvider connectionProvider,
+ SharedSessionContractImplementor session) {
this.tenantIdentifier = tenantIdentifier;
this.listener = listener;
this.connectionProvider = connectionProvider;
+ this.session = session;
}
@Override
@@ -38,11 +46,17 @@ public class ContextualJdbcConnectionAccess implements JdbcConnectionAccess, Ser
throw new HibernateException( "Tenant identifier required" );
}
+ final JdbcConnectionAcquisitionEvent jdbcConnectionAcquisitionEvent = JfrEventManager.beginJdbcConnectionAcquisitionEvent();
try {
listener.jdbcConnectionAcquisitionStart();
return connectionProvider.getConnection( tenantIdentifier );
}
finally {
+ JfrEventManager.completeJdbcConnectionAcquisitionEvent(
+ jdbcConnectionAcquisitionEvent,
+ session,
+ tenantIdentifier
+ );
listener.jdbcConnectionAcquisitionEnd();
}
}
@@ -53,11 +67,13 @@ public class ContextualJdbcConnectionAccess implements JdbcConnectionAccess, Ser
throw new HibernateException( "Tenant identifier required" );
}
+ final JdbcConnectionReleaseEvent jdbcConnectionReleaseEvent = JfrEventManager.beginJdbcConnectionReleaseEvent();
try {
listener.jdbcConnectionReleaseStart();
connectionProvider.releaseConnection( tenantIdentifier, connection );
}
finally {
+ JfrEventManager.completeJdbcConnectionReleaseEvent( jdbcConnectionReleaseEvent, session, tenantIdentifier );
listener.jdbcConnectionReleaseEnd();
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/internal/NonContextualJdbcConnectionAccess.java b/hibernate-core/src/main/java/org/hibernate/internal/NonContextualJdbcConnectionAccess.java
index 82df15f40f..42143d22fa 100644
--- a/hibernate-core/src/main/java/org/hibernate/internal/NonContextualJdbcConnectionAccess.java
+++ b/hibernate-core/src/main/java/org/hibernate/internal/NonContextualJdbcConnectionAccess.java
@@ -14,6 +14,10 @@ import java.util.Objects;
import org.hibernate.SessionEventListener;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
+import org.hibernate.event.jfr.internal.JfrEventManager;
+import org.hibernate.event.jfr.JdbcConnectionAcquisitionEvent;
+import org.hibernate.event.jfr.JdbcConnectionReleaseEvent;
/**
* @author Steve Ebersole
@@ -21,34 +25,45 @@ import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
public class NonContextualJdbcConnectionAccess implements JdbcConnectionAccess, Serializable {
private final SessionEventListener listener;
private final ConnectionProvider connectionProvider;
+ private final SharedSessionContractImplementor session;
public NonContextualJdbcConnectionAccess(
SessionEventListener listener,
- ConnectionProvider connectionProvider) {
+ ConnectionProvider connectionProvider,
+ SharedSessionContractImplementor session) {
Objects.requireNonNull( listener );
Objects.requireNonNull( connectionProvider );
this.listener = listener;
this.connectionProvider = connectionProvider;
+ this.session = session;
}
@Override
public Connection obtainConnection() throws SQLException {
+ final JdbcConnectionAcquisitionEvent jdbcConnectionAcquisitionEvent = JfrEventManager.beginJdbcConnectionAcquisitionEvent();
try {
listener.jdbcConnectionAcquisitionStart();
return connectionProvider.getConnection();
}
finally {
+ JfrEventManager.completeJdbcConnectionAcquisitionEvent(
+ jdbcConnectionAcquisitionEvent,
+ session,
+ null
+ );
listener.jdbcConnectionAcquisitionEnd();
}
}
@Override
public void releaseConnection(Connection connection) throws SQLException {
+ final JdbcConnectionReleaseEvent jdbcConnectionReleaseEvent = JfrEventManager.beginJdbcConnectionReleaseEvent();
try {
listener.jdbcConnectionReleaseStart();
connectionProvider.closeConnection( connection );
}
finally {
+ JfrEventManager.completeJdbcConnectionReleaseEvent( jdbcConnectionReleaseEvent, session, null );
listener.jdbcConnectionReleaseEnd();
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java
index eb44f02607..a9785b52e1 100644
--- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java
@@ -18,7 +18,6 @@ import java.sql.Connection;
import java.sql.NClob;
import java.sql.SQLException;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -69,6 +68,7 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.Status;
import org.hibernate.engine.transaction.spi.TransactionImplementor;
import org.hibernate.engine.transaction.spi.TransactionObserver;
+import org.hibernate.event.jfr.internal.JfrEventManager;
import org.hibernate.event.jfr.SessionClosedEvent;
import org.hibernate.event.jfr.SessionOpenEvent;
import org.hibernate.event.spi.AutoFlushEvent;
@@ -108,9 +108,7 @@ import org.hibernate.event.spi.ResolveNaturalIdEventListener;
import org.hibernate.event.spi.SaveOrUpdateEvent;
import org.hibernate.event.spi.SaveOrUpdateEventListener;
import org.hibernate.graph.GraphSemantic;
-import org.hibernate.graph.internal.RootGraphImpl;
import org.hibernate.graph.spi.RootGraphImplementor;
-import org.hibernate.internal.build.AllowNonPortable;
import org.hibernate.internal.util.ExceptionHelper;
import org.hibernate.jpa.internal.LegacySpecHelper;
import org.hibernate.jpa.internal.util.ConfigurationHelper;
@@ -141,7 +139,6 @@ import org.hibernate.type.descriptor.WrapperOptions;
import jakarta.persistence.CacheRetrieveMode;
import jakarta.persistence.CacheStoreMode;
-import jakarta.persistence.EntityGraph;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityNotFoundException;
import jakarta.persistence.FlushModeType;
@@ -228,14 +225,10 @@ public class SessionImpl
// TODO: this is unused and can be removed
private transient boolean isEnforcingFetchGraph;
- @AllowNonPortable
public SessionImpl(SessionFactoryImpl factory, SessionCreationOptions options) {
super( factory, options );
- final SessionOpenEvent sessionOpenEvent = new SessionOpenEvent();
- if ( sessionOpenEvent.isEnabled() ) {
- sessionOpenEvent.begin();
- }
+ final SessionOpenEvent sessionOpenEvent = JfrEventManager.beginSessionOpenEvent();
persistenceContext = createPersistenceContext();
actionQueue = createActionQueue();
@@ -282,13 +275,7 @@ public class SessionImpl
log.tracef( "Opened Session [%s] at timestamp: %s", getSessionIdentifier(), currentTimeMillis() );
}
- if ( sessionOpenEvent.isEnabled() ) {
- sessionOpenEvent.end();
- if ( sessionOpenEvent.shouldCommit() ) {
- sessionOpenEvent.sessionIdentifier = getSessionIdentifier().toString();
- sessionOpenEvent.commit();
- }
- }
+ JfrEventManager.completeSessionOpenEvent( sessionOpenEvent, this );
}
private FlushMode getInitialFlushMode() {
@@ -425,16 +412,12 @@ public class SessionImpl
closeWithoutOpenChecks();
}
- @AllowNonPortable
public void closeWithoutOpenChecks() throws HibernateException {
if ( log.isTraceEnabled() ) {
log.tracef( "Closing session [%s]", getSessionIdentifier() );
}
- final SessionClosedEvent sessionClosedEvent = new SessionClosedEvent();
- if ( sessionClosedEvent.isEnabled() ) {
- sessionClosedEvent.begin();
- }
+ final SessionClosedEvent sessionClosedEvent = JfrEventManager.beginSessionClosedEvent();
// todo : we want this check if usage is JPA, but not native Hibernate usage
final SessionFactoryImplementor sessionFactory = getSessionFactory();
@@ -459,13 +442,7 @@ public class SessionImpl
statistics.closeSession();
}
- if ( sessionClosedEvent.isEnabled() ) {
- sessionClosedEvent.end();
- if ( sessionClosedEvent.shouldCommit() ) {
- sessionClosedEvent.sessionIdentifier = getSessionIdentifier().toString();
- sessionClosedEvent.commit();
- }
- }
+ JfrEventManager.completeSessionClosedEvent( sessionClosedEvent, this );
}
private boolean isTransactionInProgressAndNotMarkedForRollback() {
diff --git a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/CacheEntityLoaderHelper.java b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/CacheEntityLoaderHelper.java
index e6dc71f90b..e21cdc09d6 100644
--- a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/CacheEntityLoaderHelper.java
+++ b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/CacheEntityLoaderHelper.java
@@ -273,7 +273,7 @@ public class CacheEntityLoaderHelper {
source.getTenantIdentifier()
);
- final Object ce = CacheHelper.fromSharedCache( source, ck, persister.getCacheAccessStrategy() );
+ final Object ce = CacheHelper.fromSharedCache( source, ck, persister, persister.getCacheAccessStrategy() );
final StatisticsImplementor statistics = factory.getStatistics();
if ( statistics.isStatisticsEnabled() ) {
if ( ce == null ) {
diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java
index e6b55e87e3..aedae13850 100644
--- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java
+++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java
@@ -1537,7 +1537,7 @@ public abstract class AbstractEntityPersister
if ( session.getCacheMode().isGetEnabled() && canReadFromCache() && isLazyPropertiesCacheable() ) {
final EntityDataAccess cacheAccess = getCacheAccessStrategy();
final Object cacheKey = cacheAccess.generateCacheKey(id, this, session.getFactory(), session.getTenantIdentifier() );
- final Object ce = CacheHelper.fromSharedCache( session, cacheKey, cacheAccess );
+ final Object ce = CacheHelper.fromSharedCache( session, cacheKey, this, cacheAccess );
if ( ce != null ) {
final CacheEntry cacheEntry = (CacheEntry) getCacheEntryStructure().destructure( ce, factory );
final Object initializedValue = initializeLazyPropertiesFromCache( fieldName, entity, session, entry, cacheEntry );
@@ -4148,7 +4148,7 @@ public abstract class AbstractEntityPersister
final EntityDataAccess cache = getCacheAccessStrategy();
final String tenantId = session.getTenantIdentifier();
final Object ck = cache.generateCacheKey( id, this, session.getFactory(), tenantId );
- final Object ce = CacheHelper.fromSharedCache( session, ck, getCacheAccessStrategy() );
+ final Object ce = CacheHelper.fromSharedCache( session, ck, this, getCacheAccessStrategy() );
if ( ce != null ) {
return false;
}
diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/StandardJdbcMutationExecutor.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/StandardJdbcMutationExecutor.java
index 4b2a337005..d23731591b 100644
--- a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/StandardJdbcMutationExecutor.java
+++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/StandardJdbcMutationExecutor.java
@@ -13,6 +13,8 @@ import java.util.function.Function;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
+import org.hibernate.event.jfr.JdbcPreparedStatementExecutionEvent;
+import org.hibernate.event.jfr.internal.JfrEventManager;
import org.hibernate.query.spi.QueryOptions;
import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor;
import org.hibernate.sql.exec.spi.ExecutionContext;
@@ -79,12 +81,14 @@ public class StandardJdbcMutationExecutor implements JdbcMutationExecutor {
}
session.getEventListenerManager().jdbcExecuteStatementStart();
+ final JdbcPreparedStatementExecutionEvent jdbcPreparedStatementExecutionEvent = JfrEventManager.beginJdbcPreparedStatementExecutionEvent();
try {
int rows = preparedStatement.executeUpdate();
expectationCheck.accept( rows, preparedStatement );
return rows;
}
finally {
+ JfrEventManager.completeJdbcPreparedStatementExecutionEvent( jdbcPreparedStatementExecutionEvent, finalSql );
session.getEventListenerManager().jdbcExecuteStatementEnd();
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityInitializer.java
index 9745ee4b4c..bc7447423e 100644
--- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityInitializer.java
+++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityInitializer.java
@@ -28,6 +28,8 @@ import org.hibernate.engine.spi.SessionEventListenerManager;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.Status;
+import org.hibernate.event.jfr.CachePutEvent;
+import org.hibernate.event.jfr.internal.JfrEventManager;
import org.hibernate.event.spi.PreLoadEvent;
import org.hibernate.event.spi.PreLoadEventListener;
import org.hibernate.internal.util.StringHelper;
@@ -977,19 +979,35 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
//
// we need to be careful not to clobber the lock here in the cache so that it can be rolled back if need be
if ( persistenceContext.wasInsertedDuringTransaction( concreteDescriptor, entityIdentifier) ) {
- cacheAccess.update(
- session,
- cacheKey,
- concreteDescriptor.getCacheEntryStructure().structure( cacheEntry ),
- version,
- version
- );
+ boolean update = false;
+ final CachePutEvent cachePutEvent = JfrEventManager.beginCachePutEvent();
+ try {
+ update = cacheAccess.update(
+ session,
+ cacheKey,
+ concreteDescriptor.getCacheEntryStructure().structure( cacheEntry ),
+ version,
+ version
+ );
+ }
+ finally {
+ JfrEventManager.completeCachePutEvent(
+ cachePutEvent,
+ session,
+ cacheAccess,
+ concreteDescriptor,
+ update,
+ JfrEventManager.CacheActionDescription.ENTITY_UPDATE
+ );
+ }
}
else {
final SessionEventListenerManager eventListenerManager = session.getEventListenerManager();
+ boolean put = false;
+ final CachePutEvent cachePutEvent = JfrEventManager.beginCachePutEvent();
try {
eventListenerManager.cachePutStart();
- final boolean put = cacheAccess.putFromLoad(
+ put = cacheAccess.putFromLoad(
session,
cacheKey,
concreteDescriptor.getCacheEntryStructure().structure( cacheEntry ),
@@ -997,13 +1015,20 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
//useMinimalPuts( session, entityEntry )
false
);
-
+ }
+ finally {
+ JfrEventManager.completeCachePutEvent(
+ cachePutEvent,
+ session,
+ cacheAccess,
+ concreteDescriptor,
+ put,
+ JfrEventManager.CacheActionDescription.ENTITY_LOAD
+ );
final StatisticsImplementor statistics = factory.getStatistics();
if ( put && statistics.isStatisticsEnabled() ) {
statistics.entityCachePut( rootEntityDescriptor.getNavigableRole(), cacheAccess.getRegion().getName() );
}
- }
- finally {
eventListenerManager.cachePutEnd();
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/ResultsHelper.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/ResultsHelper.java
index 5febe87525..1d18124070 100644
--- a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/ResultsHelper.java
+++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/ResultsHelper.java
@@ -22,6 +22,8 @@ import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SessionEventListenerManager;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
+import org.hibernate.event.jfr.CachePutEvent;
+import org.hibernate.event.jfr.internal.JfrEventManager;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.metamodel.mapping.ModelPart;
@@ -286,9 +288,11 @@ public class ResultsHelper {
// CollectionRegionAccessStrategy has no update, so avoid putting uncommitted data via putFromLoad
if ( isPutFromLoad ) {
final SessionEventListenerManager eventListenerManager = session.getEventListenerManager();
+ final CachePutEvent cachePutEvent = JfrEventManager.beginCachePutEvent();
+ boolean put = false;
try {
eventListenerManager.cachePutStart();
- final boolean put = cacheAccess.putFromLoad(
+ put = cacheAccess.putFromLoad(
session,
cacheKey,
collectionDescriptor.getCacheEntryStructure().structure( entry ),
@@ -296,6 +300,17 @@ public class ResultsHelper {
factory.getSessionFactoryOptions().isMinimalPutsEnabled()
&& session.getCacheMode()!= CacheMode.REFRESH
);
+ }
+ finally {
+ JfrEventManager.completeCachePutEvent(
+ cachePutEvent,
+ session,
+ cacheAccess,
+ collectionDescriptor,
+ put,
+ JfrEventManager.CacheActionDescription.COLLECTION_INSERT
+ );
+ eventListenerManager.cachePutEnd();
final StatisticsImplementor statistics = factory.getStatistics();
if ( put && statistics.isStatisticsEnabled() ) {
@@ -304,9 +319,7 @@ public class ResultsHelper {
collectionDescriptor.getCacheAccessStrategy().getRegion().getName()
);
}
- }
- finally {
- eventListenerManager.cachePutEnd();
+
}
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/DeferredResultSetAccess.java b/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/DeferredResultSetAccess.java
index a9c5e83667..55898424df 100644
--- a/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/DeferredResultSetAccess.java
+++ b/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/DeferredResultSetAccess.java
@@ -20,6 +20,8 @@ import org.hibernate.dialect.pagination.NoopLimitHandler;
import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
import org.hibernate.engine.spi.SessionEventListenerManager;
import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.event.jfr.JdbcPreparedStatementExecutionEvent;
+import org.hibernate.event.jfr.internal.JfrEventManager;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.query.spi.Limit;
@@ -235,11 +237,13 @@ public class DeferredResultSetAccess extends AbstractResultSetAccess {
if ( sqlStatementLogger.getLogSlowQuery() > 0 ) {
executeStartNanos = System.nanoTime();
}
+ final JdbcPreparedStatementExecutionEvent jdbcPreparedStatementExecutionEvent = JfrEventManager.beginJdbcPreparedStatementExecutionEvent();
try {
eventListenerManager.jdbcExecuteStatementStart();
resultSet = wrapResultSet( preparedStatement.executeQuery() );
}
finally {
+ JfrEventManager.completeJdbcPreparedStatementExecutionEvent( jdbcPreparedStatementExecutionEvent, finalSql );
eventListenerManager.jdbcExecuteStatementEnd();
sqlStatementLogger.logSlowQuery( finalSql, executeStartNanos, context() );
}
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jdbc/internal/AggressiveReleaseTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jdbc/internal/AggressiveReleaseTest.java
index e9c57cd1c5..eac9332b15 100644
--- a/hibernate-core/src/test/java/org/hibernate/orm/test/jdbc/internal/AggressiveReleaseTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jdbc/internal/AggressiveReleaseTest.java
@@ -124,11 +124,12 @@ public class AggressiveReleaseTest extends BaseSessionFactoryFunctionalTest {
JdbcCoordinatorImpl jdbcCoord = (JdbcCoordinatorImpl) session.getJdbcCoordinator();
ResourceRegistry resourceRegistry = jdbcCoord.getLogicalConnection().getResourceRegistry();
try {
+ String sql = "insert into SANDBOX_JDBC_TST( ID, NAME ) values ( ?, ? )";
PreparedStatement ps = jdbcCoord.getStatementPreparer().prepareStatement(
- "insert into SANDBOX_JDBC_TST( ID, NAME ) values ( ?, ? )" );
+ sql );
ps.setLong( 1, 1 );
ps.setString( 2, "name" );
- jdbcCoord.getResultSetReturn().execute( ps );
+ jdbcCoord.getResultSetReturn().execute( ps, sql );
assertTrue( jdbcCoord.getLogicalConnection().getResourceRegistry().hasRegisteredResources() );
assertEquals( 1, connectionProvider.getAcquiredConnections().size() );
assertEquals( 0, connectionProvider.getReleasedConnections().size() );
@@ -161,11 +162,12 @@ public class AggressiveReleaseTest extends BaseSessionFactoryFunctionalTest {
ResourceRegistry resourceRegistry = jdbcCoord.getLogicalConnection().getResourceRegistry();
try {
+ String sql = "insert into SANDBOX_JDBC_TST( ID, NAME ) values ( ?, ? )";
PreparedStatement ps = jdbcCoord.getStatementPreparer().prepareStatement(
- "insert into SANDBOX_JDBC_TST( ID, NAME ) values ( ?, ? )" );
+ sql );
ps.setLong( 1, 1 );
ps.setString( 2, "name" );
- jdbcCoord.getResultSetReturn().execute( ps );
+ jdbcCoord.getResultSetReturn().execute( ps , sql);
assertTrue( resourceRegistry.hasRegisteredResources() );
assertEquals( 1, connectionProvider.getAcquiredConnections().size() );
assertEquals( 0, connectionProvider.getReleasedConnections().size() );
@@ -177,7 +179,7 @@ public class AggressiveReleaseTest extends BaseSessionFactoryFunctionalTest {
assertEquals( 1, connectionProvider.getReleasedConnections().size() );
// open a result set and hold it open...
- final String sql = "select * from SANDBOX_JDBC_TST";
+ sql = "select * from SANDBOX_JDBC_TST";
ps = jdbcCoord.getStatementPreparer().prepareStatement( sql );
jdbcCoord.getResultSetReturn().extract( ps, sql );
assertTrue( resourceRegistry.hasRegisteredResources() );
@@ -225,11 +227,12 @@ public class AggressiveReleaseTest extends BaseSessionFactoryFunctionalTest {
ResourceRegistry resourceRegistry = jdbcCoord.getLogicalConnection().getResourceRegistry();
try {
+ String sql = "insert into SANDBOX_JDBC_TST( ID, NAME ) values ( ?, ? )";
PreparedStatement ps = jdbcCoord.getStatementPreparer().prepareStatement(
- "insert into SANDBOX_JDBC_TST( ID, NAME ) values ( ?, ? )" );
+ sql );
ps.setLong( 1, 1 );
ps.setString( 2, "name" );
- jdbcCoord.getResultSetReturn().execute( ps );
+ jdbcCoord.getResultSetReturn().execute( ps , sql);
assertTrue( resourceRegistry.hasRegisteredResources() );
assertEquals( 1, connectionProvider.getAcquiredConnections().size() );
assertEquals( 0, connectionProvider.getReleasedConnections().size() );
@@ -243,7 +246,7 @@ public class AggressiveReleaseTest extends BaseSessionFactoryFunctionalTest {
jdbcCoord.disableReleases();
// open a result set...
- final String sql = "select * from SANDBOX_JDBC_TST";
+ sql = "select * from SANDBOX_JDBC_TST";
ps = jdbcCoord.getStatementPreparer().prepareStatement( sql );
jdbcCoord.getResultSetReturn().extract( ps, sql );
assertTrue( resourceRegistry.hasRegisteredResources() );
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jdbc/internal/BasicConnectionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jdbc/internal/BasicConnectionTest.java
index 922aa6e463..96776f66d2 100644
--- a/hibernate-core/src/test/java/org/hibernate/orm/test/jdbc/internal/BasicConnectionTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jdbc/internal/BasicConnectionTest.java
@@ -38,9 +38,10 @@ public class BasicConnectionTest extends BaseCoreFunctionalTestCase {
SessionImplementor sessionImpl = (SessionImplementor) session;
boolean caught = false;
try {
+ String sql = "select count(*) from NON_EXISTENT";
PreparedStatement ps = sessionImpl.getJdbcCoordinator().getStatementPreparer()
- .prepareStatement( "select count(*) from NON_EXISTENT" );
- sessionImpl.getJdbcCoordinator().getResultSetReturn().execute( ps );
+ .prepareStatement( sql );
+ sessionImpl.getJdbcCoordinator().getResultSetReturn().execute( ps, sql );
}
catch ( JDBCException ok ) {
caught = true;
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/sql/refcursor/CursorFromCallableTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/refcursor/CursorFromCallableTest.java
index 4d860c8270..783f29d2c9 100644
--- a/hibernate-core/src/test/java/org/hibernate/orm/test/sql/refcursor/CursorFromCallableTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/refcursor/CursorFromCallableTest.java
@@ -116,7 +116,7 @@ public class CursorFromCallableTest extends BaseCoreFunctionalTestCase {
PreparedStatement preparedStatement = null;
try {
preparedStatement = statementPreparer.prepareStatement( sql );
- resultSetReturn.execute( preparedStatement );
+ resultSetReturn.execute( preparedStatement, sql );
}
finally {
if ( preparedStatement != null ) {
diff --git a/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/DirtyCalculationEventTests.java b/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/DirtyCalculationEventTests.java
new file mode 100644
index 0000000000..d057514096
--- /dev/null
+++ b/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/DirtyCalculationEventTests.java
@@ -0,0 +1,96 @@
+package org.hibernate.orm.test.event.jfr;
+
+import java.util.List;
+
+import org.hibernate.engine.spi.Status;
+import org.hibernate.event.jfr.DirtyCalculationEvent;
+
+import org.hibernate.testing.orm.junit.DomainModel;
+import org.hibernate.testing.orm.junit.SessionFactory;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jdk.jfr.consumer.RecordedEvent;
+import org.moditect.jfrunit.EnableEvent;
+import org.moditect.jfrunit.JfrEventTest;
+import org.moditect.jfrunit.JfrEvents;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@JfrEventTest
+@DomainModel(annotatedClasses = {
+ DirtyCalculationEventTests.TestEntity.class,
+})
+@SessionFactory
+public class DirtyCalculationEventTests {
+ public JfrEvents jfrEvents = new JfrEvents();
+
+ @BeforeAll
+ public void setUp(SessionFactoryScope scope){
+ scope.inTransaction(
+ session ->{
+ TestEntity entity = new TestEntity( 1, "name_1" );
+ session.persist( entity );
+ }
+ );
+ }
+
+ @Test
+ @EnableEvent(DirtyCalculationEvent.NAME)
+ public void testFlushEvent(SessionFactoryScope scope) {
+ jfrEvents.reset();
+ String sessionId = scope.fromTransaction(
+ session -> {
+ TestEntity testEntity = session.load( TestEntity.class, 1 );
+ testEntity.setName( "new name" );
+ return session.getSessionIdentifier().toString();
+ }
+ );
+ List events = jfrEvents.events()
+ .filter(
+ recordedEvent ->
+ {
+ String eventName = recordedEvent.getEventType().getName();
+ return eventName.equals( DirtyCalculationEvent.NAME );
+ }
+ ).toList();
+ assertThat( events ).hasSize( 1 );
+
+ RecordedEvent event = events.get( 0 );
+ assertThat( event.getEventType().getName() )
+ .isEqualTo( DirtyCalculationEvent.NAME );
+ assertThat( event.getLong( "executionTime" ) ).isGreaterThan( 0 );
+ assertThat( event.getString( "sessionIdentifier" ) )
+ .isEqualTo( sessionId );
+ assertThat( event.getString( "entityName" ) )
+ .isEqualTo( TestEntity.class.getName() );
+ assertThat( event.getString( "entityStatus" ) )
+ .isEqualTo( Status.MANAGED.name() );
+ assertThat( event.getBoolean( "dirty" ) )
+ .isTrue();
+ }
+
+ @Entity(name = "TestEntity")
+ public static class TestEntity {
+ @Id
+ private Integer id;
+
+ private String name;
+
+ public TestEntity() {
+ }
+
+ public TestEntity(Integer id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+ }
+
+}
diff --git a/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/JdbcBatchExecutionEventTests.java b/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/JdbcBatchExecutionEventTests.java
new file mode 100644
index 0000000000..e1864298ed
--- /dev/null
+++ b/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/JdbcBatchExecutionEventTests.java
@@ -0,0 +1,112 @@
+package org.hibernate.orm.test.event.jfr;
+
+import java.util.List;
+import java.util.Locale;
+
+import org.hibernate.cfg.AvailableSettings;
+import org.hibernate.event.jfr.JdbcBatchExecutionEvent;
+
+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 jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jdk.jfr.consumer.RecordedEvent;
+import org.moditect.jfrunit.EnableEvent;
+import org.moditect.jfrunit.JfrEventTest;
+import org.moditect.jfrunit.JfrEvents;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@JfrEventTest
+@DomainModel(annotatedClasses = {
+ JdbcBatchExecutionEventTests.TestEntity.class
+})
+@SessionFactory
+@ServiceRegistry(
+ settings = @Setting(name = AvailableSettings.STATEMENT_BATCH_SIZE, value = "5")
+)
+public class JdbcBatchExecutionEventTests {
+ public JfrEvents jfrEvents = new JfrEvents();
+
+
+ @Test
+ @EnableEvent(JdbcBatchExecutionEvent.NAME)
+ public void testJdbcBatchExecutionEvent(SessionFactoryScope scope) {
+ jfrEvents.reset();
+ scope.inTransaction(
+ session -> {
+ for ( int i = 2; i < 10; i++ ) {
+ TestEntity entity = new TestEntity( i, "name_" + i );
+ session.persist( entity );
+ }
+ session.flush();
+ final List events = jfrEvents.events()
+ .filter(
+ recordedEvent ->
+ {
+ String eventName = recordedEvent.getEventType().getName();
+ return eventName.equals( JdbcBatchExecutionEvent.NAME );
+ }
+ ).toList();
+ assertThat( events ).hasSize( 2 );
+
+ RecordedEvent jdbcBatchExecutionEvent = events.get( 0 );
+ assertThat( jdbcBatchExecutionEvent.getEventType().getName() )
+ .isEqualTo( JdbcBatchExecutionEvent.NAME );
+ assertThat( jdbcBatchExecutionEvent.getLong( "executionTime" ) ).isGreaterThan( 0 );
+ assertThat( jdbcBatchExecutionEvent.getString( "sql" ).toLowerCase( Locale.ROOT ) )
+ .contains( "insert into " );
+
+ jdbcBatchExecutionEvent = events.get( 1 );
+ assertThat( jdbcBatchExecutionEvent.getEventType().getName() )
+ .isEqualTo( JdbcBatchExecutionEvent.NAME );
+ assertThat( jdbcBatchExecutionEvent.getLong( "executionTime" ) ).isGreaterThan( 0 );
+ assertThat( jdbcBatchExecutionEvent.getString( "sql" ).toLowerCase( Locale.ROOT ) )
+ .contains( "insert into " );
+ }
+ );
+
+ }
+
+ @Test
+ @EnableEvent(JdbcBatchExecutionEvent.NAME)
+ public void testJdbcBatchExecutionEventNoFired(SessionFactoryScope scope) {
+ jfrEvents.reset();
+ scope.inTransaction(
+ session -> {
+ }
+ );
+ final List events = jfrEvents.events()
+ .filter(
+ recordedEvent ->
+ {
+ String eventName = recordedEvent.getEventType().getName();
+ return eventName.equals( JdbcBatchExecutionEvent.NAME );
+ }
+ ).toList();
+
+ assertThat( events ).hasSize( 0 );
+ }
+
+ @Entity(name = "TestEntity")
+ public static class TestEntity {
+ @Id
+ private Integer id;
+
+ private String name;
+
+ public TestEntity() {
+ }
+
+ public TestEntity(Integer id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+ }
+
+}
diff --git a/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/JdbcConnectionEventTests.java b/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/JdbcConnectionEventTests.java
new file mode 100644
index 0000000000..b65362cc56
--- /dev/null
+++ b/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/JdbcConnectionEventTests.java
@@ -0,0 +1,108 @@
+package org.hibernate.orm.test.event.jfr;
+
+import java.util.List;
+
+import org.hibernate.event.jfr.JdbcConnectionAcquisitionEvent;
+import org.hibernate.event.jfr.JdbcConnectionReleaseEvent;
+
+import org.hibernate.testing.orm.junit.DomainModel;
+import org.hibernate.testing.orm.junit.SessionFactory;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.junit.jupiter.api.Test;
+
+import jdk.jfr.consumer.RecordedEvent;
+import org.moditect.jfrunit.EnableEvent;
+import org.moditect.jfrunit.JfrEventTest;
+import org.moditect.jfrunit.JfrEvents;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@JfrEventTest
+@DomainModel
+@SessionFactory
+public class JdbcConnectionEventTests {
+ public JfrEvents jfrEvents = new JfrEvents();
+
+ @Test
+ @EnableEvent(JdbcConnectionAcquisitionEvent.NAME)
+ @EnableEvent(JdbcConnectionReleaseEvent.NAME)
+ public void testJdbcConnectionAcquisition(SessionFactoryScope scope) {
+ // starting a transaction should trigger the acquisition of the connection
+ String expectedSessionId = scope.fromTransaction(
+ session -> {
+ final List events = jfrEvents.events()
+ .filter(
+ recordedEvent ->
+ {
+ String eventName = recordedEvent.getEventType().getName();
+ return eventName.equals( JdbcConnectionAcquisitionEvent.NAME )
+ || eventName.equals( JdbcConnectionReleaseEvent.NAME );
+ }
+ ).toList();
+ assertThat( events ).hasSize( 1 );
+ RecordedEvent event = events.get( 0 );
+ assertThat( event.getEventType().getName() )
+ .isEqualTo( JdbcConnectionAcquisitionEvent.NAME );
+ String sessionId = session.getSessionIdentifier().toString();
+ assertThat( event.getString( "sessionIdentifier" ) ).isEqualTo( sessionId );
+ jfrEvents.reset();
+
+ return sessionId;
+ }
+ );
+
+ final List events = jfrEvents.events()
+ .filter(
+ recordedEvent ->
+ {
+ String eventName = recordedEvent.getEventType().getName();
+ return eventName.equals( JdbcConnectionAcquisitionEvent.NAME )
+ || eventName.equals( JdbcConnectionReleaseEvent.NAME );
+ }
+ ).toList();
+ assertThat( events ).hasSize( 1 );
+ RecordedEvent event = events.get( 0 );
+ assertThat( event.getEventType().getName() ).isEqualTo( JdbcConnectionReleaseEvent.NAME );
+ /*
+ Disabled the following check, not sure why but the retrieved `sessionIdentifier` is null,
+ checked with Flight Recorder and the value is correctly set to the session id value
+ */
+
+// assertThat( event.getString( "sessionIdentifier" ) ).isEqualTo( expectedSessionId );
+ }
+
+ @Test
+ @EnableEvent(JdbcConnectionAcquisitionEvent.NAME)
+ @EnableEvent(JdbcConnectionReleaseEvent.NAME)
+ public void testJdbcConnectionAcquisitionNoFired(SessionFactoryScope scope) {
+ jfrEvents.reset();
+
+ // starting a session should not trigger the acquisition/release of the connection
+ scope.inSession(
+ session -> {
+ final List events = jfrEvents.events()
+ .filter(
+ recordedEvent ->
+ {
+ String eventName = recordedEvent.getEventType().getName();
+ return eventName.equals( JdbcConnectionAcquisitionEvent.NAME )
+ || eventName.equals( JdbcConnectionReleaseEvent.NAME );
+ }
+ ).toList();
+ assertThat( events ).hasSize( 0 );
+ jfrEvents.reset();
+ }
+ );
+ final List events = jfrEvents.events()
+ .filter(
+ recordedEvent ->
+ {
+ String eventName = recordedEvent.getEventType().getName();
+ return eventName.equals( JdbcConnectionAcquisitionEvent.NAME )
+ || eventName.equals( JdbcConnectionReleaseEvent.NAME );
+ }
+ ).toList();
+ assertThat( events ).hasSize( 0 );
+ }
+
+}
diff --git a/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/JdbcPreparedStatementEventTests.java b/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/JdbcPreparedStatementEventTests.java
new file mode 100644
index 0000000000..e9ac9347e8
--- /dev/null
+++ b/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/JdbcPreparedStatementEventTests.java
@@ -0,0 +1,95 @@
+package org.hibernate.orm.test.event.jfr;
+
+import java.util.List;
+import java.util.Locale;
+
+import org.hibernate.event.jfr.JdbcPreparedStatementCreationEvent;
+import org.hibernate.event.jfr.JdbcPreparedStatementExecutionEvent;
+
+import org.hibernate.testing.orm.junit.DomainModel;
+import org.hibernate.testing.orm.junit.SessionFactory;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.junit.jupiter.api.Test;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jdk.jfr.consumer.RecordedEvent;
+import org.moditect.jfrunit.EnableEvent;
+import org.moditect.jfrunit.JfrEventTest;
+import org.moditect.jfrunit.JfrEvents;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@JfrEventTest
+@DomainModel(annotatedClasses = JdbcPreparedStatementEventTests.TestEntity.class)
+@SessionFactory
+public class JdbcPreparedStatementEventTests {
+ public JfrEvents jfrEvents = new JfrEvents();
+
+ @Test
+ @EnableEvent(JdbcPreparedStatementCreationEvent.NAME)
+ @EnableEvent(JdbcPreparedStatementExecutionEvent.NAME)
+ public void testJdbcPreparedStatementEvent(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ session.createQuery( "select t from TestEntity t" ).list();
+ final List events = jfrEvents.events()
+ .filter(
+ recordedEvent ->
+ {
+ String eventName = recordedEvent.getEventType().getName();
+ return eventName.equals( JdbcPreparedStatementCreationEvent.NAME )
+ || eventName.equals( JdbcPreparedStatementExecutionEvent.NAME );
+ }
+ ).toList();
+ assertThat( events ).hasSize( 2 );
+
+ RecordedEvent preparedStatementCreationEvent = events.get( 0 );
+ assertThat( preparedStatementCreationEvent.getEventType().getName() )
+ .isEqualTo( JdbcPreparedStatementCreationEvent.NAME );
+ assertThat( preparedStatementCreationEvent.getLong( "executionTime" ) ).isGreaterThan( 0 );
+ assertThat( preparedStatementCreationEvent.getString( "sql" ).toLowerCase( Locale.ROOT ) )
+ .contains( "select " );
+
+ RecordedEvent preparedStatementExecutionEvent = events.get( 1 );
+ assertThat( preparedStatementExecutionEvent.getEventType().getName() )
+ .isEqualTo( JdbcPreparedStatementExecutionEvent.NAME );
+ assertThat( preparedStatementExecutionEvent.getLong( "executionTime" ) ).isGreaterThan( 0 );
+ assertThat( preparedStatementExecutionEvent.getString( "sql" ) )
+ .isEqualTo( preparedStatementCreationEvent.getString( "sql" ) );
+ }
+ );
+
+ }
+
+ @Test
+ @EnableEvent(JdbcPreparedStatementCreationEvent.NAME)
+ @EnableEvent(JdbcPreparedStatementExecutionEvent.NAME)
+ public void testJdbcPreparedStatementEventNoFired(SessionFactoryScope scope) {
+ jfrEvents.reset();
+ scope.inTransaction(
+ session -> {
+
+ }
+ );
+ final List events = jfrEvents.events()
+ .filter(
+ recordedEvent ->
+ {
+ String eventName = recordedEvent.getEventType().getName();
+ return eventName.equals( JdbcPreparedStatementCreationEvent.NAME )
+ || eventName.equals( JdbcPreparedStatementExecutionEvent.NAME );
+ }
+ ).toList();
+
+ assertThat( events ).hasSize( 0 );
+ }
+
+ @Entity(name = "TestEntity")
+ public static class TestEntity {
+ @Id
+ private Long id;
+
+ private String name;
+ }
+}
diff --git a/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/cache/CacheGetEventTests.java b/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/cache/CacheGetEventTests.java
new file mode 100644
index 0000000000..a5f32ab47d
--- /dev/null
+++ b/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/cache/CacheGetEventTests.java
@@ -0,0 +1,125 @@
+package org.hibernate.orm.test.event.jfr.cache;
+
+import java.util.List;
+
+import org.hibernate.cfg.AvailableSettings;
+import org.hibernate.event.jfr.CacheGetEvent;
+import org.hibernate.event.jfr.JdbcBatchExecutionEvent;
+
+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.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import jakarta.persistence.Cacheable;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jdk.jfr.consumer.RecordedEvent;
+import org.moditect.jfrunit.EnableEvent;
+import org.moditect.jfrunit.JfrEventTest;
+import org.moditect.jfrunit.JfrEvents;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@JfrEventTest
+@DomainModel(annotatedClasses = {
+ CacheGetEventTests.TestEntity.class,
+})
+@SessionFactory
+@ServiceRegistry(
+ settings = {
+ @Setting(name = AvailableSettings.USE_SECOND_LEVEL_CACHE, value = "true"),
+ }
+)
+public class CacheGetEventTests {
+ public JfrEvents jfrEvents = new JfrEvents();
+
+ @BeforeAll
+ public void setUp(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ TestEntity entity = new TestEntity( 1, "name_1" );
+ session.persist( entity );
+ }
+ );
+ }
+
+ @Test
+ @EnableEvent(JdbcBatchExecutionEvent.NAME)
+ public void testCacheGetEvent(SessionFactoryScope scope) {
+ jfrEvents.reset();
+ scope.inTransaction(
+ session -> {
+ TestEntity testEntity = session.find( TestEntity.class, 1 );
+
+ List events = jfrEvents.events()
+ .filter(
+ recordedEvent ->
+ {
+ String eventName = recordedEvent.getEventType().getName();
+ return eventName.equals( CacheGetEvent.NAME );
+ }
+ ).toList();
+ assertThat( events ).hasSize( 1 );
+
+ RecordedEvent event = events.get( 0 );
+ assertThat( event.getEventType().getName() )
+ .isEqualTo( CacheGetEvent.NAME );
+ assertThat( event.getLong( "executionTime" ) ).isGreaterThan( 0 );
+ assertThat( event.getString( "sessionIdentifier" ) )
+ .isEqualTo( session.getSessionIdentifier().toString() );
+ assertThat( event.getString( "entityName" ) )
+ .isEqualTo( TestEntity.class.getName() );
+ assertThat( event.getBoolean( "isNaturalId" ) ).isFalse();
+ assertThat( event.getBoolean( "hit" ) ).isTrue();
+ assertThat( event.getString( "regionName" ) ).isNotNull();
+ }
+ );
+
+ }
+
+ @Test
+ @EnableEvent(JdbcBatchExecutionEvent.NAME)
+ public void testCacheGetEventNoFired(SessionFactoryScope scope) {
+ jfrEvents.reset();
+ scope.inTransaction(
+ session -> {
+
+ }
+ );
+ List events = jfrEvents.events()
+ .filter(
+ recordedEvent ->
+ {
+ String eventName = recordedEvent.getEventType().getName();
+ return eventName.equals( CacheGetEvent.NAME );
+ }
+ ).toList();
+ assertThat( events ).hasSize( 0 );
+ }
+
+ @Entity(name = "TestEntity")
+ @Cacheable
+ public static class TestEntity {
+ @Id
+ private Integer id;
+
+ private String name;
+
+ public TestEntity() {
+ }
+
+ public TestEntity(Integer id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+ }
+
+}
diff --git a/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/cache/EntityInsertCachePutEventTests.java b/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/cache/EntityInsertCachePutEventTests.java
new file mode 100644
index 0000000000..5a287a1f0b
--- /dev/null
+++ b/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/cache/EntityInsertCachePutEventTests.java
@@ -0,0 +1,168 @@
+package org.hibernate.orm.test.event.jfr.cache;
+
+import java.util.List;
+
+import org.hibernate.annotations.Cache;
+import org.hibernate.annotations.CacheConcurrencyStrategy;
+import org.hibernate.cfg.AvailableSettings;
+import org.hibernate.event.jfr.CachePutEvent;
+import org.hibernate.event.jfr.JdbcBatchExecutionEvent;
+import org.hibernate.event.jfr.internal.JfrEventManager;
+import org.hibernate.orm.test.cache.CacheRegionStatisticsTest;
+
+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 jakarta.persistence.Cacheable;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jdk.jfr.consumer.RecordedEvent;
+import org.moditect.jfrunit.EnableEvent;
+import org.moditect.jfrunit.JfrEventTest;
+import org.moditect.jfrunit.JfrEvents;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@JfrEventTest
+@DomainModel(annotatedClasses = {
+ EntityInsertCachePutEventTests.TestEntity.class,
+ EntityInsertCachePutEventTests.AnotherTestEntity.class,
+})
+@SessionFactory
+@ServiceRegistry(
+ settings =
+ {
+ @Setting(name = AvailableSettings.USE_SECOND_LEVEL_CACHE, value = "true"),
+ }
+)
+public class EntityInsertCachePutEventTests {
+ public JfrEvents jfrEvents = new JfrEvents();
+
+ @Test
+ @EnableEvent(JdbcBatchExecutionEvent.NAME)
+ public void testCachePutEvent(SessionFactoryScope scope) {
+ jfrEvents.reset();
+ scope.inTransaction(
+ session -> {
+ TestEntity entity = new TestEntity( 1, "name_1" );
+ session.persist( entity );
+
+ session.flush();
+ List events = jfrEvents.events()
+ .filter(
+ recordedEvent ->
+ {
+ String eventName = recordedEvent.getEventType().getName();
+ return eventName.equals( CachePutEvent.NAME );
+ }
+ ).toList();
+ assertThat( events ).hasSize( 1 );
+
+ RecordedEvent event = events.get( 0 );
+ assertThat( event.getEventType().getName() )
+ .isEqualTo( CachePutEvent.NAME );
+ assertThat( event.getLong( "executionTime" ) ).isGreaterThan( 0 );
+ assertThat( event.getString( "sessionIdentifier" ) )
+ .isEqualTo( session.getSessionIdentifier().toString() );
+ assertThat( event.getString( "entityName" ) ).isEqualTo( TestEntity.class.getName() );
+ // cache strategy is READ_WRITE so no cache insert happened
+ assertThat( event.getBoolean( "cacheChanged" ) ).isFalse();
+ assertThat( event.getString( "regionName" ) ).isNotNull();
+ assertThat( event.getString( "description" ) ).isEqualTo( JfrEventManager.CacheActionDescription.ENTITY_INSERT.getText() );
+
+ jfrEvents.reset();
+ AnotherTestEntity anotherTestEntity = new AnotherTestEntity( 1, "name_1" );
+ session.persist( anotherTestEntity );
+
+ session.flush();
+ events = jfrEvents.events()
+ .filter(
+ recordedEvent ->
+ {
+ String eventName = recordedEvent.getEventType().getName();
+ return eventName.equals( CachePutEvent.NAME );
+ }
+ ).toList();
+ assertThat( events ).hasSize( 1 );
+
+ event = events.get( 0 );
+ assertThat( event.getEventType().getName() )
+ .isEqualTo( CachePutEvent.NAME );
+ assertThat( event.getLong( "executionTime" ) ).isGreaterThan( 0 );
+ assertThat( event.getString( "sessionIdentifier" ) )
+ .isEqualTo( session.getSessionIdentifier().toString() );
+ assertThat( event.getString( "entityName" ) ).isEqualTo( AnotherTestEntity.class.getName() );
+ // cache strategy is TRANSACTIONAL so cache insert should happen
+ assertThat( event.getBoolean( "cacheChanged" ) ).isTrue();
+ assertThat( event.getString( "regionName" ) ).isNotNull();
+ assertThat( event.getBoolean( "isNaturalId" ) ).isFalse();
+ assertThat( event.getString( "description" ) ).isEqualTo( JfrEventManager.CacheActionDescription.ENTITY_INSERT.getText() );
+ }
+ );
+
+ }
+
+ @Test
+ @EnableEvent(JdbcBatchExecutionEvent.NAME)
+ public void testJdbcBatchExecutionEventNoFired(SessionFactoryScope scope) {
+ jfrEvents.reset();
+ scope.inTransaction(
+ session -> {
+ session.createQuery(
+ "from TestEntity",
+ CacheRegionStatisticsTest.Dog.class
+ ).setCacheable( false ).getResultList();
+ }
+ );
+ final List events = jfrEvents.events()
+ .filter(
+ recordedEvent ->
+ {
+ String eventName = recordedEvent.getEventType().getName();
+ return eventName.equals( CachePutEvent.NAME );
+ }
+ ).toList();
+
+ assertThat( events ).hasSize( 0 );
+ }
+
+ @Entity(name = "TestEntity")
+ @Cacheable
+ public static class TestEntity {
+ @Id
+ private Integer id;
+
+ private String name;
+
+ public TestEntity() {
+ }
+
+ public TestEntity(Integer id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+ }
+
+ @Entity(name = "AnotherTestEntity")
+ @Cacheable
+ @Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
+ public static class AnotherTestEntity {
+ @Id
+ private Integer id;
+
+ private String name;
+
+ public AnotherTestEntity() {
+ }
+
+ public AnotherTestEntity(Integer id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+ }
+
+}
diff --git a/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/cache/EntityUpdateCachePutEventTests.java b/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/cache/EntityUpdateCachePutEventTests.java
new file mode 100644
index 0000000000..927a144f6c
--- /dev/null
+++ b/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/cache/EntityUpdateCachePutEventTests.java
@@ -0,0 +1,167 @@
+package org.hibernate.orm.test.event.jfr.cache;
+
+import java.util.List;
+
+import org.hibernate.annotations.Cache;
+import org.hibernate.annotations.CacheConcurrencyStrategy;
+import org.hibernate.cfg.AvailableSettings;
+import org.hibernate.event.jfr.CachePutEvent;
+import org.hibernate.event.jfr.JdbcBatchExecutionEvent;
+import org.hibernate.event.jfr.internal.JfrEventManager;
+
+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.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import jakarta.persistence.Cacheable;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jdk.jfr.consumer.RecordedEvent;
+import org.moditect.jfrunit.EnableEvent;
+import org.moditect.jfrunit.JfrEventTest;
+import org.moditect.jfrunit.JfrEvents;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@JfrEventTest
+@DomainModel(annotatedClasses = {
+ EntityUpdateCachePutEventTests.TestEntity.class,
+ EntityUpdateCachePutEventTests.AnotherTestEntity.class,
+})
+@SessionFactory
+@ServiceRegistry(
+ settings = {
+ @Setting(name = AvailableSettings.USE_SECOND_LEVEL_CACHE, value = "true"),
+ }
+)
+public class EntityUpdateCachePutEventTests {
+ public JfrEvents jfrEvents = new JfrEvents();
+
+ @BeforeAll
+ public void setUp(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ TestEntity entity = new TestEntity( 1, "name_1" );
+ session.persist( entity );
+ AnotherTestEntity anotherTestEntity = new AnotherTestEntity( 1, "name_1" );
+ session.persist( anotherTestEntity );
+ }
+ );
+ }
+
+ @Test
+ @EnableEvent(JdbcBatchExecutionEvent.NAME)
+ public void testCachePutEvent(SessionFactoryScope scope) {
+ jfrEvents.reset();
+ scope.inTransaction(
+ session -> {
+
+ TestEntity testEntity = session.find( TestEntity.class, 1 );
+
+ testEntity.setName( "Another name" );
+ session.flush();
+ List events = jfrEvents.events()
+ .filter(
+ recordedEvent ->
+ {
+ String eventName = recordedEvent.getEventType().getName();
+ return eventName.equals( CachePutEvent.NAME );
+ }
+ ).toList();
+ assertThat( events ).hasSize( 1 );
+
+ RecordedEvent event = events.get( 0 );
+ assertThat( event.getEventType().getName() )
+ .isEqualTo( CachePutEvent.NAME );
+ assertThat( event.getLong( "executionTime" ) ).isGreaterThan( 0 );
+ assertThat( event.getString( "sessionIdentifier" ) )
+ .isEqualTo( session.getSessionIdentifier().toString() );
+ assertThat( event.getString( "entityName" ) ).isEqualTo( TestEntity.class.getName() );
+ // cache strategy is READ_WRITE so no cache insert happened
+ assertThat( event.getBoolean( "cacheChanged" ) ).isFalse();
+ assertThat( event.getBoolean( "isNaturalId" ) ).isFalse();
+ assertThat( event.getString( "regionName" ) ).isNotNull();
+ assertThat( event.getString( "description" ) ).isEqualTo( JfrEventManager.CacheActionDescription.ENTITY_UPDATE.getText() );
+
+ jfrEvents.reset();
+
+ AnotherTestEntity anotherTestEntity = session.find( AnotherTestEntity.class, 1 );
+
+ anotherTestEntity.setName( "Another name" );
+ session.flush();
+
+ events = jfrEvents.events()
+ .filter(
+ recordedEvent ->
+ {
+ String eventName = recordedEvent.getEventType().getName();
+ return eventName.equals( CachePutEvent.NAME );
+ }
+ ).toList();
+ assertThat( events ).hasSize( 1 );
+
+ event = events.get( 0 );
+ assertThat( event.getEventType().getName() )
+ .isEqualTo( CachePutEvent.NAME );
+ assertThat( event.getLong( "executionTime" ) ).isGreaterThan( 0 );
+ assertThat( event.getString( "sessionIdentifier" ) )
+ .isEqualTo( session.getSessionIdentifier().toString() );
+ assertThat( event.getString( "entityName" ) ).isEqualTo( AnotherTestEntity.class.getName() );
+ // cache strategy is TRANSACTIONAL so cache insert should happen
+ assertThat( event.getBoolean( "cacheChanged" ) ).isTrue();
+ assertThat( event.getString( "regionName" ) ).isNotNull();
+ assertThat( event.getBoolean( "isNaturalId" ) ).isFalse();
+ assertThat( event.getString( "description" ) ).isEqualTo( JfrEventManager.CacheActionDescription.ENTITY_UPDATE.getText() );
+ }
+ );
+
+ }
+
+ @Entity(name = "TestEntity")
+ @Cacheable
+ public static class TestEntity {
+ @Id
+ private Integer id;
+
+ private String name;
+
+ public TestEntity() {
+ }
+
+ public TestEntity(Integer id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+ }
+
+ @Entity(name = "AnotherTestEntity")
+ @Cacheable
+ @Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
+ public static class AnotherTestEntity {
+ @Id
+ private Integer id;
+
+ private String name;
+
+ public AnotherTestEntity() {
+ }
+
+ public AnotherTestEntity(Integer id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+ }
+
+}
diff --git a/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/cache/NaturalIdGetCacheTests.java b/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/cache/NaturalIdGetCacheTests.java
new file mode 100644
index 0000000000..e0bc61c528
--- /dev/null
+++ b/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/cache/NaturalIdGetCacheTests.java
@@ -0,0 +1,128 @@
+package org.hibernate.orm.test.event.jfr.cache;
+
+import java.util.List;
+
+import org.hibernate.annotations.Cache;
+import org.hibernate.annotations.CacheConcurrencyStrategy;
+import org.hibernate.annotations.NaturalId;
+import org.hibernate.annotations.NaturalIdCache;
+import org.hibernate.cfg.AvailableSettings;
+import org.hibernate.event.jfr.CacheGetEvent;
+
+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 jakarta.persistence.Cacheable;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jdk.jfr.consumer.RecordedEvent;
+import org.moditect.jfrunit.EnableEvent;
+import org.moditect.jfrunit.JfrEventTest;
+import org.moditect.jfrunit.JfrEvents;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@JfrEventTest
+@DomainModel(annotatedClasses = {
+ NaturalIdGetCacheTests.TestEntity.class
+})
+@SessionFactory
+@ServiceRegistry(
+ settings = {
+ @Setting(name = AvailableSettings.USE_SECOND_LEVEL_CACHE, value = "true"),
+ }
+)
+public class NaturalIdGetCacheTests {
+
+ public JfrEvents jfrEvents = new JfrEvents();
+
+ @Test
+ @EnableEvent(CacheGetEvent.NAME)
+ public void testCacheGetEvent(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ TestEntity testEntity = new TestEntity( 2, 4, 5 );
+ session.persist( testEntity );
+ }
+ );
+
+ scope.inTransaction(
+ session -> {
+ jfrEvents.reset();
+ TestEntity load = session.byNaturalId( TestEntity.class )
+ .using( "code", 4 )
+ .using( "item", 5 )
+ .load();
+ List events = jfrEvents.events()
+ .filter(
+ recordedEvent ->
+ {
+ String eventName = recordedEvent.getEventType().getName();
+ return eventName.equals( CacheGetEvent.NAME );
+ }
+ ).toList();
+
+ assertThat( events ).hasSize( 2 );
+
+ RecordedEvent event = events.get( 0 );
+ assertThat( event.getEventType().getName() )
+ .isEqualTo( CacheGetEvent.NAME );
+ assertThat( event.getLong( "executionTime" ) ).isGreaterThan( 0 );
+ assertThat( event.getString( "sessionIdentifier" ) )
+ .isEqualTo( session.getSessionIdentifier().toString() );
+ assertThat( event.getString( "entityName" ) )
+ .isEqualTo( TestEntity.class.getName() );
+ assertThat( event.getBoolean( "isNaturalId" ) ).isTrue();
+ assertThat( event.getBoolean( "hit" ) ).isTrue();
+ assertThat( event.getString( "regionName" ) ).isNotNull();
+
+ event = events.get( 1 );
+ assertThat( event.getEventType().getName() )
+ .isEqualTo( CacheGetEvent.NAME );
+ assertThat( event.getLong( "executionTime" ) ).isGreaterThan( 0 );
+ assertThat( event.getString( "sessionIdentifier" ) )
+ .isEqualTo( session.getSessionIdentifier().toString() );
+ assertThat( event.getString( "entityName" ) )
+ .isEqualTo( TestEntity.class.getName() );
+ assertThat( event.getBoolean( "isNaturalId" ) ).isFalse();
+ assertThat( event.getBoolean( "hit" ) ).isTrue();
+ assertThat( event.getString( "regionName" ) ).isNotNull();
+
+
+ }
+ );
+
+ }
+
+
+ @Entity(name = "TestEntity")
+ @Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
+ @Cacheable
+ @NaturalIdCache
+ public static class TestEntity {
+
+ @Id
+ private Integer id;
+
+ @NaturalId
+ private Integer code;
+
+ @NaturalId
+ private Integer item;
+
+ private String description = "A description ...";
+
+ protected TestEntity() {
+ }
+
+ public TestEntity(Integer id, Integer code, Integer item) {
+ this.id = id;
+ this.code = code;
+ this.item = item;
+ }
+ }
+}
diff --git a/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/cache/NaturalIdPutCacheTests.java b/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/cache/NaturalIdPutCacheTests.java
new file mode 100644
index 0000000000..f5e10f3230
--- /dev/null
+++ b/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/cache/NaturalIdPutCacheTests.java
@@ -0,0 +1,115 @@
+package org.hibernate.orm.test.event.jfr.cache;
+
+import java.util.List;
+
+import org.hibernate.annotations.Cache;
+import org.hibernate.annotations.CacheConcurrencyStrategy;
+import org.hibernate.annotations.NaturalId;
+import org.hibernate.annotations.NaturalIdCache;
+import org.hibernate.cfg.AvailableSettings;
+import org.hibernate.event.jfr.CachePutEvent;
+import org.hibernate.event.jfr.internal.JfrEventManager;
+
+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 jakarta.persistence.Cacheable;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jdk.jfr.consumer.RecordedEvent;
+import org.moditect.jfrunit.EnableEvent;
+import org.moditect.jfrunit.JfrEventTest;
+import org.moditect.jfrunit.JfrEvents;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@JfrEventTest
+@DomainModel(annotatedClasses = {
+ NaturalIdPutCacheTests.TestEntity.class
+})
+@SessionFactory
+@ServiceRegistry(
+ settings = {
+ @Setting(name = AvailableSettings.USE_SECOND_LEVEL_CACHE, value = "true"),
+ }
+)
+public class NaturalIdPutCacheTests {
+
+ public JfrEvents jfrEvents = new JfrEvents();
+
+ @Test
+ @EnableEvent(CachePutEvent.NAME)
+ public void testCachePutEvent(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ TestEntity testEntity = new TestEntity( 1, 2, 3 );
+ session.persist( testEntity );
+ session.flush();
+ List events = jfrEvents.events()
+ .filter(
+ recordedEvent ->
+ {
+ String eventName = recordedEvent.getEventType().getName();
+ return eventName.equals( CachePutEvent.NAME );
+ }
+ ).toList();
+ assertThat( events ).hasSize( 2 );
+ RecordedEvent event = events.get( 0 );
+ assertThat( event.getEventType().getName() )
+ .isEqualTo( CachePutEvent.NAME );
+ assertThat( event.getLong( "executionTime" ) ).isGreaterThan( 0 );
+ assertThat( event.getString( "sessionIdentifier" ) )
+ .isEqualTo( session.getSessionIdentifier().toString() );
+ assertThat( event.getString( "entityName" ) ).isEqualTo( TestEntity.class.getName() );
+ assertThat( event.getBoolean( "cacheChanged" ) ).isTrue();
+ assertThat( event.getBoolean( "isNaturalId" ) ).isFalse();
+ assertThat( event.getString( "regionName" ) ).isNotNull();
+ assertThat( event.getString( "description" ) ).isEqualTo( JfrEventManager.CacheActionDescription.ENTITY_INSERT.getText() );
+
+ event = events.get( 1 );
+ assertThat( event.getEventType().getName() )
+ .isEqualTo( CachePutEvent.NAME );
+ assertThat( event.getLong( "executionTime" ) ).isGreaterThan( 0 );
+ assertThat( event.getString( "sessionIdentifier" ) )
+ .isEqualTo( session.getSessionIdentifier().toString() );
+ assertThat( event.getString( "entityName" ) ).isEqualTo( TestEntity.class.getName() );
+ // cache strategy is READ_WRITE so no cache insert happened
+ assertThat( event.getBoolean( "cacheChanged" ) ).isTrue();
+ assertThat( event.getBoolean( "isNaturalId" ) ).isTrue();
+ assertThat( event.getString( "regionName" ) ).isNotNull();
+ assertThat( event.getString( "description" ) ).isEqualTo( JfrEventManager.CacheActionDescription.ENTITY_INSERT.getText() );
+ }
+ );
+ }
+
+ @Entity(name = "TestEntity")
+ @Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
+ @Cacheable
+ @NaturalIdCache
+ public static class TestEntity {
+
+ @Id
+ private Integer id;
+
+ @NaturalId
+ private Integer code;
+
+ @NaturalId
+ private Integer item;
+
+ private String description = "A description ...";
+
+ protected TestEntity() {
+ }
+
+ public TestEntity(Integer id, Integer code, Integer item) {
+ this.id = id;
+ this.code = code;
+ this.item = item;
+ }
+ }
+}
diff --git a/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/cache/QueryCachePutEventTests.java b/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/cache/QueryCachePutEventTests.java
new file mode 100644
index 0000000000..4d52f948dd
--- /dev/null
+++ b/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/cache/QueryCachePutEventTests.java
@@ -0,0 +1,131 @@
+package org.hibernate.orm.test.event.jfr.cache;
+
+import java.util.List;
+
+import org.hibernate.cfg.AvailableSettings;
+import org.hibernate.event.jfr.CachePutEvent;
+import org.hibernate.event.jfr.JdbcBatchExecutionEvent;
+import org.hibernate.event.jfr.internal.JfrEventManager;
+import org.hibernate.orm.test.cache.CacheRegionStatisticsTest;
+
+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.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jdk.jfr.consumer.RecordedEvent;
+import org.moditect.jfrunit.EnableEvent;
+import org.moditect.jfrunit.JfrEventTest;
+import org.moditect.jfrunit.JfrEvents;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@JfrEventTest
+@DomainModel(annotatedClasses = {
+ QueryCachePutEventTests.TestEntity.class,
+})
+@SessionFactory
+@ServiceRegistry(
+ settings =
+ {
+ @Setting(name = AvailableSettings.USE_SECOND_LEVEL_CACHE, value = "true"),
+ @Setting(name = AvailableSettings.USE_QUERY_CACHE, value = "true")
+ }
+)
+public class QueryCachePutEventTests {
+ public JfrEvents jfrEvents = new JfrEvents();
+
+ @BeforeAll
+ public void setUp(SessionFactoryScope scope) {
+ scope.inTransaction(
+ session -> {
+ for ( int i = 2; i < 10; i++ ) {
+ TestEntity entity = new TestEntity( i, "name_" + i );
+ session.persist( entity );
+ }
+ }
+ );
+ }
+
+ @Test
+ @EnableEvent(JdbcBatchExecutionEvent.NAME)
+ public void testCachePutEvent(SessionFactoryScope scope) {
+ jfrEvents.reset();
+ scope.inTransaction(
+ session -> {
+ List dogs = session.createQuery(
+ "from TestEntity",
+ CacheRegionStatisticsTest.Dog.class
+ ).setCacheable( true ).getResultList();
+
+ final List events = jfrEvents.events()
+ .filter(
+ recordedEvent ->
+ {
+ String eventName = recordedEvent.getEventType().getName();
+ return eventName.equals( CachePutEvent.NAME );
+ }
+ ).toList();
+ assertThat( events ).hasSize( 1 );
+
+ RecordedEvent event = events.get( 0 );
+ assertThat( event.getEventType().getName() )
+ .isEqualTo( CachePutEvent.NAME );
+ assertThat( event.getLong( "executionTime" ) ).isGreaterThan( 0 );
+ assertThat( event.getString( "sessionIdentifier" ) )
+ .isEqualTo( session.getSessionIdentifier().toString() );
+ assertThat( event.getBoolean( "cacheChanged" ) ).isTrue();
+ assertThat( event.getString( "regionName" ) ).isNotNull();
+ assertThat( event.getBoolean( "isNaturalId" ) ).isFalse();
+ assertThat( event.getString( "description" ) ).isEqualTo( JfrEventManager.CacheActionDescription.QUERY_RESULT.getText() );
+ }
+ );
+
+ }
+
+ @Test
+ @EnableEvent(JdbcBatchExecutionEvent.NAME)
+ public void testJdbcBatchExecutionEventNoFired(SessionFactoryScope scope) {
+ jfrEvents.reset();
+ scope.inTransaction(
+ session -> {
+ session.createQuery(
+ "from TestEntity",
+ CacheRegionStatisticsTest.Dog.class
+ ).setCacheable( false ).getResultList();
+ }
+ );
+ final List events = jfrEvents.events()
+ .filter(
+ recordedEvent ->
+ {
+ String eventName = recordedEvent.getEventType().getName();
+ return eventName.equals( CachePutEvent.NAME );
+ }
+ ).toList();
+
+ assertThat( events ).hasSize( 0 );
+ }
+
+ @Entity(name = "TestEntity")
+ public static class TestEntity {
+ @Id
+ private Integer id;
+
+ private String name;
+
+ public TestEntity() {
+ }
+
+ public TestEntity(Integer id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+ }
+
+}
diff --git a/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/flush/AutoFlushTests.java b/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/flush/AutoFlushTests.java
new file mode 100644
index 0000000000..53b1988af3
--- /dev/null
+++ b/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/flush/AutoFlushTests.java
@@ -0,0 +1,103 @@
+package org.hibernate.orm.test.event.jfr.flush;
+
+import java.util.List;
+
+import org.hibernate.event.jfr.FlushEvent;
+import org.hibernate.event.jfr.PartialFlushEvent;
+
+import org.hibernate.testing.orm.junit.DomainModel;
+import org.hibernate.testing.orm.junit.SessionFactory;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.junit.jupiter.api.Test;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jdk.jfr.consumer.RecordedEvent;
+import org.moditect.jfrunit.EnableEvent;
+import org.moditect.jfrunit.JfrEventTest;
+import org.moditect.jfrunit.JfrEvents;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@JfrEventTest
+@DomainModel(annotatedClasses = {
+ AutoFlushTests.TestEntity.class,
+})
+@SessionFactory
+public class AutoFlushTests {
+ public JfrEvents jfrEvents = new JfrEvents();
+
+ @Test
+ @EnableEvent(FlushEvent.NAME)
+ @EnableEvent(PartialFlushEvent.NAME)
+ public void testFlushEvent(SessionFactoryScope scope) {
+ jfrEvents.reset();
+ scope.inTransaction(
+ session -> {
+ TestEntity entity = new TestEntity( 1, "name_1" );
+ session.persist( entity );
+ session.createQuery( "select t from TestEntity t" ).list();
+ List events = jfrEvents.events()
+ .filter(
+ recordedEvent ->
+ {
+ String eventName = recordedEvent.getEventType().getName();
+ return eventName.equals( FlushEvent.NAME );
+ }
+ ).toList();
+ assertThat( events ).hasSize( 1 );
+
+ RecordedEvent event = events.get( 0 );
+ assertThat( event.getEventType().getName() )
+ .isEqualTo( FlushEvent.NAME );
+ assertThat( event.getLong( "executionTime" ) ).isGreaterThan( 0 );
+ assertThat( event.getString( "sessionIdentifier" ) )
+ .isEqualTo( session.getSessionIdentifier().toString() );
+ assertThat( event.getInt( "numberOfEntitiesProcessed" ) )
+ .isEqualTo( 1 );
+ assertThat( event.getInt( "numberOfCollectionsProcessed" ) ).isEqualTo( 0 );
+ assertThat( event.getBoolean( "isAutoFlush" ) ).isTrue();
+
+ events = jfrEvents.events()
+ .filter(
+ recordedEvent ->
+ {
+ String eventName = recordedEvent.getEventType().getName();
+ return eventName.equals( PartialFlushEvent.NAME );
+ }
+ ).toList();
+ event = events.get( 0 );
+ assertThat( event.getEventType().getName() )
+ .isEqualTo( PartialFlushEvent.NAME );
+ assertThat( event.getLong( "executionTime" ) ).isGreaterThan( 0 );
+ assertThat( event.getString( "sessionIdentifier" ) )
+ .isEqualTo( session.getSessionIdentifier().toString() );
+ assertThat( event.getInt( "numberOfEntitiesProcessed" ) )
+ .isEqualTo( 1 );
+ assertThat( event.getInt( "numberOfCollectionsProcessed" ) ).isEqualTo( 0 );
+ assertThat( event.getBoolean( "isAutoFlush" ) ).isTrue();
+ }
+ );
+ }
+
+ @Entity(name = "TestEntity")
+ public static class TestEntity {
+ @Id
+ private Integer id;
+
+ private String name;
+
+ public TestEntity() {
+ }
+
+ public TestEntity(Integer id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+ }
+
+}
diff --git a/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/flush/ExplicitFlushTests.java b/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/flush/ExplicitFlushTests.java
new file mode 100644
index 0000000000..e12da23143
--- /dev/null
+++ b/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/flush/ExplicitFlushTests.java
@@ -0,0 +1,82 @@
+package org.hibernate.orm.test.event.jfr.flush;
+
+import java.util.List;
+
+import org.hibernate.event.jfr.FlushEvent;
+
+import org.hibernate.testing.orm.junit.DomainModel;
+import org.hibernate.testing.orm.junit.SessionFactory;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.junit.jupiter.api.Test;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jdk.jfr.consumer.RecordedEvent;
+import org.moditect.jfrunit.EnableEvent;
+import org.moditect.jfrunit.JfrEventTest;
+import org.moditect.jfrunit.JfrEvents;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@JfrEventTest
+@DomainModel(annotatedClasses = {
+ ExplicitFlushTests.TestEntity.class,
+})
+@SessionFactory
+public class ExplicitFlushTests {
+ public JfrEvents jfrEvents = new JfrEvents();
+
+ @Test
+ @EnableEvent(FlushEvent.NAME)
+ public void testFlushEvent(SessionFactoryScope scope) {
+ jfrEvents.reset();
+ scope.inTransaction(
+ session -> {
+ TestEntity entity = new TestEntity( 1, "name_1" );
+ session.persist( entity );
+ session.flush();
+ List events = jfrEvents.events()
+ .filter(
+ recordedEvent ->
+ {
+ String eventName = recordedEvent.getEventType().getName();
+ return eventName.equals( FlushEvent.NAME );
+ }
+ ).toList();
+ assertThat( events ).hasSize( 1 );
+
+ RecordedEvent event = events.get( 0 );
+ assertThat( event.getEventType().getName() )
+ .isEqualTo( FlushEvent.NAME );
+ assertThat( event.getLong( "executionTime" ) ).isGreaterThan( 0 );
+ assertThat( event.getString( "sessionIdentifier" ) )
+ .isEqualTo( session.getSessionIdentifier().toString() );
+ assertThat( event.getInt( "numberOfEntitiesProcessed" ) )
+ .isEqualTo( 1 );
+ assertThat( event.getInt( "numberOfCollectionsProcessed" ) ).isEqualTo( 0 );
+ assertThat( event.getBoolean( "isAutoFlush" ) ).isFalse();
+ }
+ );
+ }
+
+ @Entity(name = "TestEntity")
+ public static class TestEntity {
+ @Id
+ private Integer id;
+
+ private String name;
+
+ public TestEntity() {
+ }
+
+ public TestEntity(Integer id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+ }
+
+}
diff --git a/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/flush/FlushTests.java b/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/flush/FlushTests.java
new file mode 100644
index 0000000000..b43b49d34a
--- /dev/null
+++ b/hibernate-core/src/test/java17/org/hibernate/orm/test/event/jfr/flush/FlushTests.java
@@ -0,0 +1,104 @@
+package org.hibernate.orm.test.event.jfr.flush;
+
+import java.util.List;
+
+import org.hibernate.event.jfr.FlushEvent;
+import org.hibernate.event.jfr.JdbcBatchExecutionEvent;
+
+import org.hibernate.testing.orm.junit.DomainModel;
+import org.hibernate.testing.orm.junit.SessionFactory;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.junit.jupiter.api.Test;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jdk.jfr.consumer.RecordedEvent;
+import org.moditect.jfrunit.EnableEvent;
+import org.moditect.jfrunit.JfrEventTest;
+import org.moditect.jfrunit.JfrEvents;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@JfrEventTest
+@DomainModel(annotatedClasses = {
+ FlushTests.TestEntity.class,
+})
+@SessionFactory
+public class FlushTests {
+ public JfrEvents jfrEvents = new JfrEvents();
+
+ @Test
+ @EnableEvent(FlushEvent.NAME)
+ public void testFlushEvent(SessionFactoryScope scope) {
+ jfrEvents.reset();
+ String sessionId = scope.fromTransaction(
+ session -> {
+ TestEntity entity = new TestEntity( 1, "name_1" );
+ session.persist( entity );
+ return session.getSessionIdentifier().toString();
+ }
+ );
+
+ List events = jfrEvents.events()
+ .filter(
+ recordedEvent ->
+ {
+ String eventName = recordedEvent.getEventType().getName();
+ return eventName.equals( FlushEvent.NAME );
+ }
+ ).toList();
+ assertThat( events ).hasSize( 1 );
+
+ RecordedEvent event = events.get( 0 );
+ assertThat( event.getEventType().getName() )
+ .isEqualTo( FlushEvent.NAME );
+ assertThat( event.getLong( "executionTime" ) ).isGreaterThan( 0 );
+ assertThat( event.getString( "sessionIdentifier" ) )
+ .isEqualTo( sessionId );
+ assertThat( event.getInt( "numberOfEntitiesProcessed" ) )
+ .isEqualTo( 1 );
+ assertThat( event.getInt( "numberOfCollectionsProcessed" ) ).isEqualTo( 0 );
+ assertThat( event.getBoolean( "isAutoFlush" ) ).isFalse();
+ }
+
+ @Test
+ @EnableEvent(JdbcBatchExecutionEvent.NAME)
+ public void testFlushNoFired(SessionFactoryScope scope) {
+ jfrEvents.reset();
+ scope.inTransaction(
+ session -> {
+
+ }
+ );
+ List events = jfrEvents.events()
+ .filter(
+ recordedEvent ->
+ {
+ String eventName = recordedEvent.getEventType().getName();
+ return eventName.equals( FlushEvent.NAME );
+ }
+ ).toList();
+ assertThat( events ).hasSize( 0 );
+ }
+
+ @Entity(name = "TestEntity")
+ public static class TestEntity {
+ @Id
+ private Integer id;
+
+ private String name;
+
+ public TestEntity() {
+ }
+
+ public TestEntity(Integer id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+ }
+
+}