Skip to content

Commit 704d343

Browse files
committed
HHH-17985 second-level cache invalidation for StatelessSession
1 parent 8515f08 commit 704d343

File tree

1 file changed

+51
-0
lines changed

1 file changed

+51
-0
lines changed

hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
import org.hibernate.UnresolvableObjectException;
2020
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
2121
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
22+
import org.hibernate.cache.CacheException;
2223
import org.hibernate.cache.spi.access.EntityDataAccess;
24+
import org.hibernate.cache.spi.access.SoftLock;
2325
import org.hibernate.collection.spi.CollectionSemantics;
2426
import org.hibernate.collection.spi.PersistentCollection;
2527
import org.hibernate.engine.internal.StatefulPersistenceContext;
@@ -29,6 +31,7 @@
2931
import org.hibernate.engine.spi.EntityKey;
3032
import org.hibernate.engine.spi.LoadQueryInfluencers;
3133
import org.hibernate.engine.spi.PersistenceContext;
34+
import org.hibernate.engine.spi.SharedSessionContractImplementor;
3235
import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper;
3336
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
3437
import org.hibernate.event.monitor.spi.EventMonitor;
@@ -100,6 +103,7 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
100103
private final LoadQueryInfluencers influencers;
101104
private final PersistenceContext temporaryPersistenceContext;
102105
private final boolean connectionProvided;
106+
private final List<Runnable> afterCompletions = new ArrayList<>();
103107

104108
public StatelessSessionImpl(SessionFactoryImpl factory, SessionCreationOptions options) {
105109
super( factory, options );
@@ -269,6 +273,7 @@ public void delete(String entityName, Object entity) {
269273
if ( !firePreDelete(entity, id, persister) ) {
270274
getInterceptor().onDelete( entity, id, persister.getPropertyNames(), persister.getPropertyTypes() );
271275
removeCollections( entity, id, persister );
276+
final Object ck = lockCacheItem( id, version, persister );
272277
final EventMonitor eventMonitor = getEventMonitor();
273278
final DiagnosticEvent event = eventMonitor.beginEntityDeleteEvent();
274279
boolean success = false;
@@ -279,6 +284,7 @@ public void delete(String entityName, Object entity) {
279284
finally {
280285
eventMonitor.completeEntityDeleteEvent( event, id, persister.getEntityName(), success, this );
281286
}
287+
removeCacheItem( ck, persister );
282288
firePostDelete(entity, id, persister);
283289
final StatisticsImplementor statistics = getFactory().getStatistics();
284290
if ( statistics.isStatisticsEnabled() ) {
@@ -348,6 +354,7 @@ public void update(String entityName, Object entity) {
348354
}
349355
if ( !firePreUpdate(entity, id, state, persister) ) {
350356
getInterceptor().onUpdate( entity, id, state, persister.getPropertyNames(), persister.getPropertyTypes() );
357+
final Object ck = lockCacheItem( id, oldVersion, persister );
351358
final EventMonitor eventMonitor = getEventMonitor();
352359
final DiagnosticEvent event = eventMonitor.beginEntityUpdateEvent();
353360
boolean success = false;
@@ -358,6 +365,7 @@ public void update(String entityName, Object entity) {
358365
finally {
359366
eventMonitor.completeEntityUpdateEvent( event, id, persister.getEntityName(), success, this );
360367
}
368+
removeCacheItem( ck, persister );
361369
removeAndRecreateCollections( entity, id, persister );
362370
firePostUpdate(entity, id, state, persister);
363371
final StatisticsImplementor statistics = getFactory().getStatistics();
@@ -417,6 +425,7 @@ public void upsert(String entityName, Object entity) {
417425
if ( !firePreUpsert(entity, id, state, persister) ) {
418426
getInterceptor().onUpsert( entity, id, state, persister.getPropertyNames(), persister.getPropertyTypes() );
419427
final Object oldVersion = versionToUpsert( entity, persister, state );
428+
final Object ck = lockCacheItem( id, oldVersion, persister );
420429
final EventMonitor eventMonitor = getEventMonitor();
421430
final DiagnosticEvent event = eventMonitor.beginEntityUpsertEvent();
422431
boolean success = false;
@@ -427,6 +436,7 @@ public void upsert(String entityName, Object entity) {
427436
finally {
428437
eventMonitor.completeEntityUpsertEvent( event, id, persister.getEntityName(), success, this );
429438
}
439+
removeCacheItem( ck, persister );
430440
final StatisticsImplementor statistics = getFactory().getStatistics();
431441
if ( statistics.isStatisticsEnabled() ) {
432442
statistics.upsertEntity( persister.getEntityName() );
@@ -1114,12 +1124,29 @@ public void beforeTransactionCompletion() {
11141124

11151125
@Override
11161126
public void afterTransactionCompletion(boolean successful, boolean delayed) {
1127+
processAfterCompletions();
11171128
afterTransactionCompletionEvents( successful );
11181129
if ( shouldAutoClose() && !isClosed() ) {
11191130
managedClose();
11201131
}
11211132
}
11221133

1134+
private void processAfterCompletions() {
1135+
for ( Runnable completion: afterCompletions ) {
1136+
try {
1137+
completion.run();
1138+
}
1139+
catch (CacheException ce) {
1140+
LOG.unableToReleaseCacheLock( ce );
1141+
// continue loop
1142+
}
1143+
catch (Exception e) {
1144+
throw new HibernateException( "Unable to perform afterTransactionCompletion callback: " + e.getMessage(), e );
1145+
}
1146+
}
1147+
afterCompletions.clear();
1148+
}
1149+
11231150
@Override
11241151
public boolean isTransactionInProgress() {
11251152
return connectionProvided || super.isTransactionInProgress();
@@ -1159,4 +1186,28 @@ public boolean isStatelessSession() {
11591186
return true;
11601187
}
11611188

1189+
protected Object lockCacheItem(Object id, Object previousVersion, EntityPersister persister) {
1190+
if ( persister.canWriteToCache() ) {
1191+
final SharedSessionContractImplementor session = getSession();
1192+
final EntityDataAccess cache = persister.getCacheAccessStrategy();
1193+
final Object ck = cache.generateCacheKey(
1194+
id,
1195+
persister,
1196+
session.getFactory(),
1197+
session.getTenantIdentifier()
1198+
);
1199+
final SoftLock lock = cache.lockItem( session, ck, previousVersion );
1200+
afterCompletions.add( () -> cache.unlockItem( this, ck, lock ) );
1201+
return ck;
1202+
}
1203+
else {
1204+
return null;
1205+
}
1206+
}
1207+
1208+
protected void removeCacheItem(Object ck, EntityPersister persister) {
1209+
if ( persister.canWriteToCache() ) {
1210+
persister.getCacheAccessStrategy().remove( this, ck );
1211+
}
1212+
}
11621213
}

0 commit comments

Comments
 (0)