Skip to content

Commit bd2087b

Browse files
committed
HHH-19734 Test shallow query caching with proxy presence of bytecode enhanced model
1 parent 193b15c commit bd2087b

File tree

3 files changed

+180
-5
lines changed

3 files changed

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

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
@@ -40,6 +40,7 @@ public class PersistenceUnitInfoImpl implements PersistenceUnitInfo {
4040
private List<String> mappingFiles;
4141
private List<String> managedClassNames;
4242
private boolean excludeUnlistedClasses;
43+
private ClassLoader classLoader;
4344

4445
public PersistenceUnitInfoImpl(String name) {
4546
this.name = name;
@@ -120,6 +121,15 @@ public void setExcludeUnlistedClasses(boolean excludeUnlistedClasses) {
120121
this.excludeUnlistedClasses = excludeUnlistedClasses;
121122
}
122123

124+
@Override
125+
public ClassLoader getClassLoader() {
126+
return classLoader;
127+
}
128+
129+
public void setClassLoader(ClassLoader classLoader) {
130+
this.classLoader = classLoader;
131+
}
132+
123133
@Override
124134
public String getPersistenceXMLSchemaVersion() {
125135
return null;
@@ -145,11 +155,6 @@ public URL getPersistenceUnitRootUrl() {
145155
return null;
146156
}
147157

148-
@Override
149-
public ClassLoader getClassLoader() {
150-
return null;
151-
}
152-
153158
@Override
154159
public void addTransformer(ClassTransformer transformer) {
155160

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
@@ -90,6 +90,9 @@ public static EntityManagerFactoryScope findEntityManagerFactoryScope(
9090
pui.getProperties().put( key, value )
9191
);
9292

93+
// Use the context class loader for entity loading if configured,
94+
// to make enhancement work for tests
95+
pui.setClassLoader( Thread.currentThread().getContextClassLoader() );
9396
pui.setTransactionType( emfAnn.transactionType() );
9497
pui.setCacheMode( emfAnn.sharedCacheMode() );
9598
pui.setValidationMode( emfAnn.validationMode() );

0 commit comments

Comments
 (0)