Skip to content

Commit 39267cb

Browse files
committed
HHH-19734 Test shallow query caching with proxy presence of bytecode enhanced model
1 parent 0a76cbe commit 39267cb

File tree

3 files changed

+176
-5
lines changed

3 files changed

+176
-5
lines changed
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.orm.test.jpa.query;
6+
7+
import jakarta.persistence.Entity;
8+
import jakarta.persistence.EntityManager;
9+
import jakarta.persistence.Id;
10+
import jakarta.persistence.TypedQuery;
11+
import org.hibernate.annotations.Cache;
12+
import org.hibernate.annotations.CacheConcurrencyStrategy;
13+
import org.hibernate.annotations.CacheLayout;
14+
import org.hibernate.annotations.QueryCacheLayout;
15+
import org.hibernate.cfg.AvailableSettings;
16+
import org.hibernate.engine.spi.SessionFactoryImplementor;
17+
import org.hibernate.stat.Statistics;
18+
import org.hibernate.testing.bytecode.enhancement.extension.BytecodeEnhanced;
19+
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
20+
import org.hibernate.testing.orm.junit.JiraKey;
21+
import org.hibernate.testing.orm.junit.Jpa;
22+
import org.hibernate.testing.orm.junit.Setting;
23+
import org.junit.jupiter.api.AfterEach;
24+
import org.junit.jupiter.api.BeforeEach;
25+
import org.junit.jupiter.api.Test;
26+
27+
import static org.hibernate.jpa.HibernateHints.HINT_CACHEABLE;
28+
import static org.junit.jupiter.api.Assertions.assertEquals;
29+
30+
@JiraKey("HHH-19734")
31+
@Jpa(
32+
annotatedClasses = {
33+
CachedQueryShallowWithDiscriminatorBytecodeEnhancedTest.Person.class
34+
},
35+
generateStatistics = true,
36+
properties = {
37+
@Setting(name = AvailableSettings.USE_QUERY_CACHE, value = "true"),
38+
@Setting(name = AvailableSettings.USE_SECOND_LEVEL_CACHE, value = "true")
39+
}
40+
)
41+
@BytecodeEnhanced
42+
public class CachedQueryShallowWithDiscriminatorBytecodeEnhancedTest {
43+
44+
public final static String HQL = "select p from Person p";
45+
46+
@BeforeEach
47+
public void setUp(EntityManagerFactoryScope scope) {
48+
scope.inTransaction(
49+
em -> {
50+
Person person = new Person( 1L );
51+
person.setName( "Bob" );
52+
em.persist( person );
53+
}
54+
);
55+
}
56+
57+
@AfterEach
58+
public void tearDown(EntityManagerFactoryScope scope) {
59+
scope.getEntityManagerFactory().getSchemaManager().truncate();
60+
}
61+
62+
@Test
63+
public void testCacheableQuery(EntityManagerFactoryScope scope) {
64+
65+
Statistics stats = getStatistics( scope );
66+
stats.clear();
67+
68+
// First time the query is executed, query and results are cached.
69+
scope.inTransaction(
70+
em -> {
71+
loadPersons( em );
72+
73+
assertThatAnSQLQueryHasBeenExecuted( stats );
74+
75+
assertEquals( 0, stats.getQueryCacheHitCount() );
76+
assertEquals( 1, stats.getQueryCacheMissCount() );
77+
assertEquals( 1, stats.getQueryCachePutCount() );
78+
79+
assertEquals( 0, stats.getSecondLevelCacheHitCount() );
80+
assertEquals( 0, stats.getSecondLevelCacheMissCount() );
81+
assertEquals( 0, stats.getSecondLevelCachePutCount() );
82+
}
83+
);
84+
85+
stats.clear();
86+
87+
// Second time the query is executed, list of entities are read from query cache
88+
89+
scope.inTransaction(
90+
em -> {
91+
// Create a person proxy in the persistence context to trigger the HHH-19734 error
92+
em.getReference( Person.class, 1L );
93+
94+
loadPersons( em );
95+
96+
assertThatNoSQLQueryHasBeenExecuted( stats );
97+
98+
assertEquals( 1, stats.getQueryCacheHitCount() );
99+
assertEquals( 0, stats.getQueryCacheMissCount() );
100+
assertEquals( 0, stats.getQueryCachePutCount() );
101+
102+
assertEquals( 1, stats.getSecondLevelCacheHitCount() );
103+
assertEquals( 0, stats.getSecondLevelCacheMissCount() );
104+
assertEquals( 0, stats.getSecondLevelCachePutCount() );
105+
}
106+
);
107+
108+
}
109+
110+
private static Statistics getStatistics(EntityManagerFactoryScope scope) {
111+
return ((SessionFactoryImplementor) scope.getEntityManagerFactory()).getStatistics();
112+
}
113+
114+
private static void loadPersons(EntityManager em) {
115+
TypedQuery<Person> query = em.createQuery( HQL, Person.class )
116+
.setHint( HINT_CACHEABLE, true );
117+
Person person = query.getSingleResult();
118+
assertEquals( 1L, person.getId() );
119+
assertEquals( "Bob", person.getName() );
120+
}
121+
122+
private static void assertThatAnSQLQueryHasBeenExecuted(Statistics stats) {
123+
assertEquals( 1, stats.getQueryStatistics( HQL ).getExecutionCount() );
124+
}
125+
126+
private static void assertThatNoSQLQueryHasBeenExecuted(Statistics stats) {
127+
assertEquals( 0, stats.getQueryStatistics( HQL ).getExecutionCount() );
128+
}
129+
130+
@Entity(name = "Person")
131+
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
132+
@QueryCacheLayout(layout = CacheLayout.SHALLOW)
133+
public static class Person {
134+
@Id
135+
private Long id;
136+
private String name;
137+
138+
public Person() {
139+
super();
140+
}
141+
142+
public Person(Long id) {
143+
this.id = id;
144+
}
145+
146+
public Long getId() {
147+
return id;
148+
}
149+
150+
public void setId(Long id) {
151+
this.id = id;
152+
}
153+
154+
public String getName() {
155+
return name;
156+
}
157+
158+
public void setName(String name) {
159+
this.name = name;
160+
}
161+
}
162+
163+
}

hibernate-testing/src/main/java/org/hibernate/testing/orm/jpa/PersistenceUnitInfoImpl.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public class PersistenceUnitInfoImpl implements PersistenceUnitInfo {
4444
private List<String> mappingFiles;
4545
private List<String> managedClassNames;
4646
private boolean excludeUnlistedClasses;
47+
private ClassLoader classLoader;
4748

4849
public PersistenceUnitInfoImpl(String name) {
4950
this.name = name;
@@ -142,6 +143,15 @@ public void setExcludeUnlistedClasses(boolean excludeUnlistedClasses) {
142143
this.excludeUnlistedClasses = excludeUnlistedClasses;
143144
}
144145

146+
@Override
147+
public ClassLoader getClassLoader() {
148+
return classLoader;
149+
}
150+
151+
public void setClassLoader(ClassLoader classLoader) {
152+
this.classLoader = classLoader;
153+
}
154+
145155
@Override
146156
public String getPersistenceXMLSchemaVersion() {
147157
return null;
@@ -167,11 +177,6 @@ public URL getPersistenceUnitRootUrl() {
167177
return null;
168178
}
169179

170-
@Override
171-
public ClassLoader getClassLoader() {
172-
return null;
173-
}
174-
175180
@Override
176181
public void addTransformer(ClassTransformer transformer) {
177182

hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/EntityManagerFactoryExtension.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ private static void collectProperties(PersistenceUnitInfoImpl pui, Jpa jpa) {
111111
private static PersistenceUnitInfoImpl createPersistenceUnitInfo(Jpa jpa) {
112112
final PersistenceUnitInfoImpl pui =
113113
new PersistenceUnitInfoImpl( jpa.persistenceUnitName() );
114+
// Use the context class loader for entity loading if configured,
115+
// to make enhancement work for tests
116+
pui.setClassLoader( Thread.currentThread().getContextClassLoader() );
114117
pui.setTransactionType( jpa.transactionType() );
115118
pui.setCacheMode( jpa.sharedCacheMode() );
116119
pui.setValidationMode( jpa.validationMode() );

0 commit comments

Comments
 (0)