HHH-16557 Testcase and bugfix proposal (revised by beikov)

This commit is contained in:
Guenther Demetz 2024-05-07 18:20:15 +02:00 committed by Christian Beikov
parent f9f540b848
commit 53398df5f3
5 changed files with 60 additions and 6 deletions

View File

@ -174,7 +174,7 @@ public class EntityDeleteAction extends EntityAction {
final EntityKey key = entry.getEntityKey(); final EntityKey key = entry.getEntityKey();
persistenceContext.removeEntityHolder( key ); persistenceContext.removeEntityHolder( key );
removeCacheItem( ck ); removeCacheItem( ck );
persistenceContext.getNaturalIdResolutions().removeSharedResolution( id, naturalIdValues, persister ); persistenceContext.getNaturalIdResolutions().removeSharedResolution( id, naturalIdValues, persister, true);
postDelete(); postDelete();
} }

View File

@ -433,6 +433,11 @@ public class NaturalIdResolutionsImpl implements NaturalIdResolutions, Serializa
@Override @Override
public void removeSharedResolution(Object id, Object naturalId, EntityMappingType entityDescriptor) { public void removeSharedResolution(Object id, Object naturalId, EntityMappingType entityDescriptor) {
removeSharedResolution( id, naturalId, entityDescriptor, false );
}
@Override
public void removeSharedResolution(Object id, Object naturalId, EntityMappingType entityDescriptor, boolean delayToAfterTransactionCompletion) {
final NaturalIdMapping naturalIdMapping = entityDescriptor.getNaturalIdMapping(); final NaturalIdMapping naturalIdMapping = entityDescriptor.getNaturalIdMapping();
if ( naturalIdMapping == null ) { if ( naturalIdMapping == null ) {
// nothing to do // nothing to do
@ -453,7 +458,18 @@ public class NaturalIdResolutionsImpl implements NaturalIdResolutions, Serializa
final EntityPersister persister = locatePersisterForKey( entityDescriptor.getEntityPersister() ); final EntityPersister persister = locatePersisterForKey( entityDescriptor.getEntityPersister() );
final Object naturalIdCacheKey = cacheAccess.generateCacheKey( naturalId, persister, session() ); final Object naturalIdCacheKey = cacheAccess.generateCacheKey( naturalId, persister, session() );
if ( delayToAfterTransactionCompletion ) {
session().asEventSource().getActionQueue().registerProcess(
(success, session) -> {
if ( success ) {
cacheAccess.evict( naturalIdCacheKey ); cacheAccess.evict( naturalIdCacheKey );
}
}
);
}
else {
cacheAccess.evict( naturalIdCacheKey );
}
// if ( sessionCachedNaturalIdValues != null // if ( sessionCachedNaturalIdValues != null
// && !Arrays.equals( sessionCachedNaturalIdValues, deletedNaturalIdValues ) ) { // && !Arrays.equals( sessionCachedNaturalIdValues, deletedNaturalIdValues ) ) {
@ -479,7 +495,7 @@ public class NaturalIdResolutionsImpl implements NaturalIdResolutions, Serializa
cacheResolution( pk, naturalIdValuesFromCurrentObjectState, persister ); cacheResolution( pk, naturalIdValuesFromCurrentObjectState, persister );
stashInvalidNaturalIdReference( persister, cachedNaturalIdValues ); stashInvalidNaturalIdReference( persister, cachedNaturalIdValues );
removeSharedResolution( pk, cachedNaturalIdValues, persister ); removeSharedResolution( pk, cachedNaturalIdValues, persister, false );
} }
} }

View File

@ -68,7 +68,11 @@ public interface NaturalIdResolutions {
/** /**
* Removes any cross-reference from the L2 cache * Removes any cross-reference from the L2 cache
*/ */
void removeSharedResolution(Object id, Object naturalId, EntityMappingType entityDescriptor); void removeSharedResolution(Object id, Object naturalId, EntityMappingType entityDescriptor, boolean delayToAfterTransactionCompletion);
default void removeSharedResolution(Object id, Object naturalId, EntityMappingType entityDescriptor) {
removeSharedResolution( id, naturalId, entityDescriptor, false );
}
/** /**
* Find the cached natural-id for the given identifier * Find the cached natural-id for the given identifier

View File

@ -4110,7 +4110,7 @@ public abstract class AbstractEntityPersister
? null ? null
: naturalIdMapping.extractNaturalIdFromEntityState( entitySnapshot ); : naturalIdMapping.extractNaturalIdFromEntityState( entitySnapshot );
naturalIdResolutions.removeSharedResolution( id, naturalIdSnapshot, this ); naturalIdResolutions.removeSharedResolution( id, naturalIdSnapshot, this, false );
final Object naturalId = naturalIdMapping.extractNaturalIdFromEntity( entity ); final Object naturalId = naturalIdMapping.extractNaturalIdFromEntity( entity );
naturalIdResolutions.manageLocalResolution( id, naturalId, this, CachedNaturalIdValueSource.UPDATE ); naturalIdResolutions.manageLocalResolution( id, naturalId, this, CachedNaturalIdValueSource.UPDATE );
} }

View File

@ -180,6 +180,40 @@ public abstract class CachedMutableNaturalIdTest {
); );
} }
@Test
@TestForIssue( jiraKey = "HHH-16557" )
public void testCreateDeleteRecreate(SessionFactoryScope scope) {
final Integer id = scope.fromTransaction(
(session) -> {
AllCached it = new AllCached( "it" );
session.persist(it);
session.remove(it);
// insert-remove might happen in an app driven by users GUI interactions
return it.getId();
}
);
// now recreate with same naturalId value
scope.inTransaction(
(session) -> {
AllCached it = new AllCached( "it" );
session.persist(it);
// resolving from first level cache
assertNotNull(session.bySimpleNaturalId( AllCached.class ).load( "it" ));
}
);
scope.inTransaction(
(session) -> {
// should resolve from second level cache
final AllCached shouldBeThere = session.bySimpleNaturalId( AllCached.class ).load( "it" );
assertNotNull( shouldBeThere );
assert(id.compareTo(shouldBeThere.getId()) != 0);
}
);
}
@Test @Test
@JiraKey("HHH-16558") @JiraKey("HHH-16558")
public void testCacheVerifyHits(SessionFactoryScope scope) { public void testCacheVerifyHits(SessionFactoryScope scope) {