Skip to content

Commit

Permalink
HHH-19142 StatelessSession.getMultiple() and second-level cache
Browse files Browse the repository at this point in the history
  • Loading branch information
gavinking committed Feb 17, 2025
1 parent 90780a0 commit 17c3914
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -757,19 +757,45 @@ public <T> List<T> getMultiple(Class<T> entityClass, List<Object> ids) {
throw new IllegalArgumentException("Null id");
}
}

final EntityPersister persister = requireEntityPersister( entityClass.getName() );

final List<Object> uncachedIds;
final List<T> list = new ArrayList<>( ids.size() );
if ( persister.canReadFromCache() ) {
uncachedIds = new ArrayList<>( ids.size() );
for (Object id : ids) {
final Object cachedEntity =
loadFromSecondLevelCache( this, null, LockMode.NONE, persister,
generateEntityKey( id, persister ) );
if ( cachedEntity == null ) {
uncachedIds.add( id );
list.add( null );
}
else {
//noinspection unchecked
list.add( (T) cachedEntity );
}
}
}
else {
uncachedIds = ids;
for (int i = 0; i < ids.size(); i++) {
list.add( null );
}
}

final JpaCriteriaQuery<T> query = getCriteriaBuilder().createQuery(entityClass);
final JpaRoot<T> from = query.from(entityClass);
query.where( from.get( persister.getIdentifierPropertyName() ).in(ids) );
query.where( from.get( persister.getIdentifierPropertyName() ).in(uncachedIds) );
final List<T> resultList = createSelectionQuery(query).getResultList();
final List<Object> idList = new ArrayList<>( resultList.size() );
for (T entity : resultList) {
idList.add( persister.getIdentifier(entity, this) );
}
final List<T> list = new ArrayList<>( ids.size() );
for (Object id : ids) {
final int pos = idList.indexOf(id);
list.add( pos < 0 ? null : resultList.get(pos) );
for (int i = 0; i < ids.size(); i++) {
if ( list.get(i) == null ) {
final Object id = ids.get(i);
list.set( i, resultList.stream()
.filter( entity -> entity != null && persister.getIdentifier( entity, this ).equals(id) )
.findFirst().orElse( null ) );
}
}
return list;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* SPDX-License-Identifier: LGPL-2.1-or-later
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.orm.test.stateless;

import jakarta.persistence.Cacheable;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
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 java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;

@SessionFactory(generateStatistics = true)
@DomainModel(annotatedClasses = GetMultipleFromCacheTest.Record.class)
public class GetMultipleFromCacheTest {
@Test void test(SessionFactoryScope scope) {
scope.inStatelessTransaction(s-> {
s.insert(new Record(123L,"hello earth"));
s.insert(new Record(456L,"hello mars"));
});
scope.inStatelessTransaction(s-> {
List<Record> all = s.getMultiple(Record.class, List.of(456L, 123L, 2L));
assertEquals("hello mars",all.get(0).message);
assertEquals("hello earth",all.get(1).message);
assertNull(all.get(2));
});
scope.getSessionFactory().getStatistics().clear();
scope.inStatelessTransaction(s-> {
List<Record> all = s.getMultiple(Record.class, List.of(123L, 2L, 456L));
assertEquals("hello earth",all.get(0).message);
assertEquals("hello mars",all.get(2).message);
assertNull(all.get(1));
});
assertEquals( 2,
scope.getSessionFactory().getStatistics().getSecondLevelCacheHitCount() );
}
@Entity @Cacheable
static class Record {
@Id Long id;
String message;

Record(Long id, String message) {
this.id = id;
this.message = message;
}

Record() {
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ public class GetMultipleTest {
assertEquals("hello earth",all.get(1).message);
assertNull(all.get(2));
});
scope.inStatelessTransaction(s-> {
List<Record> all = s.getMultiple(Record.class, List.of(123L, 2L, 456L));
assertEquals("hello earth",all.get(0).message);
assertEquals("hello mars",all.get(2).message);
assertNull(all.get(1));
});
}
@Entity
static class Record {
Expand Down

0 comments on commit 17c3914

Please sign in to comment.