1919import org .hibernate .UnresolvableObjectException ;
2020import org .hibernate .bytecode .enhance .spi .interceptor .EnhancementAsProxyLazinessInterceptor ;
2121import org .hibernate .bytecode .spi .BytecodeEnhancementMetadata ;
22+ import org .hibernate .cache .CacheException ;
2223import org .hibernate .cache .spi .access .EntityDataAccess ;
24+ import org .hibernate .cache .spi .access .SoftLock ;
2325import org .hibernate .collection .spi .CollectionSemantics ;
2426import org .hibernate .collection .spi .PersistentCollection ;
2527import org .hibernate .engine .internal .StatefulPersistenceContext ;
2931import org .hibernate .engine .spi .EntityKey ;
3032import org .hibernate .engine .spi .LoadQueryInfluencers ;
3133import org .hibernate .engine .spi .PersistenceContext ;
34+ import org .hibernate .engine .spi .SharedSessionContractImplementor ;
3235import org .hibernate .engine .transaction .internal .jta .JtaStatusHelper ;
3336import org .hibernate .engine .transaction .jta .platform .spi .JtaPlatform ;
3437import 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