mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-02-08 12:14:47 +00:00
HHH-13077 - Optimize query plan call count
This commit is contained in:
parent
35bd8b4b6f
commit
7ef27cbb26
@ -638,11 +638,11 @@ public QueryImplementor getNamedQuery(String name) {
|
|||||||
throw getExceptionConverter().convert( new IllegalArgumentException( "No query defined for that name [" + name + "]" ) );
|
throw getExceptionConverter().convert( new IllegalArgumentException( "No query defined for that name [" + name + "]" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected QueryImplementor createQuery(NamedQueryDefinition queryDefinition) {
|
protected QueryImpl createQuery(NamedQueryDefinition queryDefinition) {
|
||||||
String queryString = queryDefinition.getQueryString();
|
String queryString = queryDefinition.getQueryString();
|
||||||
final QueryImpl query = new QueryImpl(
|
final QueryImpl query = new QueryImpl(
|
||||||
this,
|
this,
|
||||||
getQueryPlan( queryString, false ).getParameterMetadata(),
|
getQueryPlan( queryString, false ),
|
||||||
queryString
|
queryString
|
||||||
);
|
);
|
||||||
applyQuerySettingsAndHints( query );
|
applyQuerySettingsAndHints( query );
|
||||||
@ -714,7 +714,7 @@ protected void initQueryFromNamedDefinition(Query query, NamedQueryDefinition nq
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public QueryImplementor createQuery(String queryString) {
|
public QueryImpl createQuery(String queryString) {
|
||||||
checkOpen();
|
checkOpen();
|
||||||
pulseTransactionCoordinator();
|
pulseTransactionCoordinator();
|
||||||
delayedAfterCompletion();
|
delayedAfterCompletion();
|
||||||
@ -722,7 +722,7 @@ public QueryImplementor createQuery(String queryString) {
|
|||||||
try {
|
try {
|
||||||
final QueryImpl query = new QueryImpl(
|
final QueryImpl query = new QueryImpl(
|
||||||
this,
|
this,
|
||||||
getQueryPlan( queryString, false ).getParameterMetadata(),
|
getQueryPlan( queryString, false ),
|
||||||
queryString
|
queryString
|
||||||
);
|
);
|
||||||
applyQuerySettingsAndHints( query );
|
applyQuerySettingsAndHints( query );
|
||||||
@ -822,7 +822,7 @@ public <T> QueryImplementor<T> createQuery(String queryString, Class<T> resultCl
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// do the translation
|
// do the translation
|
||||||
final QueryImplementor<T> query = createQuery( queryString );
|
final QueryImpl<T> query = createQuery( queryString );
|
||||||
resultClassChecking( resultClass, query );
|
resultClassChecking( resultClass, query );
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
@ -832,13 +832,10 @@ public <T> QueryImplementor<T> createQuery(String queryString, Class<T> resultCl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked", "WeakerAccess", "StatementWithEmptyBody"})
|
@SuppressWarnings({"unchecked", "WeakerAccess", "StatementWithEmptyBody"})
|
||||||
protected void resultClassChecking(Class resultClass, org.hibernate.Query hqlQuery) {
|
protected void resultClassChecking(Class resultClass, QueryImpl hqlQuery) {
|
||||||
// make sure the query is a select -> HHH-7192
|
// make sure the query is a select -> HHH-7192
|
||||||
final HQLQueryPlan queryPlan = getFactory().getQueryPlanCache().getHQLQueryPlan(
|
HQLQueryPlan queryPlan = hqlQuery.getQueryPlan();
|
||||||
hqlQuery.getQueryString(),
|
|
||||||
false,
|
|
||||||
getLoadQueryInfluencers().getEnabledFilters()
|
|
||||||
);
|
|
||||||
if ( queryPlan.getTranslators()[0].isManipulationStatement() ) {
|
if ( queryPlan.getTranslators()[0].isManipulationStatement() ) {
|
||||||
throw new IllegalArgumentException( "Update/delete queries cannot be typed" );
|
throw new IllegalArgumentException( "Update/delete queries cannot be typed" );
|
||||||
}
|
}
|
||||||
@ -914,7 +911,7 @@ protected <T> QueryImplementor<T> buildQueryFromName(String name, Class<T> resu
|
|||||||
|
|
||||||
@SuppressWarnings({"WeakerAccess", "unchecked"})
|
@SuppressWarnings({"WeakerAccess", "unchecked"})
|
||||||
protected <T> QueryImplementor<T> createQuery(NamedQueryDefinition namedQueryDefinition, Class<T> resultType) {
|
protected <T> QueryImplementor<T> createQuery(NamedQueryDefinition namedQueryDefinition, Class<T> resultType) {
|
||||||
final QueryImplementor query = createQuery( namedQueryDefinition );
|
final QueryImpl query = createQuery( namedQueryDefinition );
|
||||||
if ( resultType != null ) {
|
if ( resultType != null ) {
|
||||||
resultClassChecking( resultType, query );
|
resultClassChecking( resultType, query );
|
||||||
}
|
}
|
||||||
|
@ -1523,7 +1523,7 @@ public Iterator iterate(String query, QueryParameters queryParameters) throws Hi
|
|||||||
queryParameters.validateParameters();
|
queryParameters.validateParameters();
|
||||||
|
|
||||||
HQLQueryPlan plan = queryParameters.getQueryPlan();
|
HQLQueryPlan plan = queryParameters.getQueryPlan();
|
||||||
if ( plan == null ) {
|
if ( plan == null || !plan.isShallow() ) {
|
||||||
plan = getQueryPlan( query, true );
|
plan = getQueryPlan( query, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@
|
|||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("UnusedDeclaration")
|
@SuppressWarnings("UnusedDeclaratiqon")
|
||||||
public interface Query<R> extends TypedQuery<R>, org.hibernate.Query<R>, CommonQueryContract {
|
public interface Query<R> extends TypedQuery<R>, org.hibernate.Query<R>, CommonQueryContract {
|
||||||
/**
|
/**
|
||||||
* Get the QueryProducer this Query originates from.
|
* Get the QueryProducer this Query originates from.
|
||||||
|
@ -1450,13 +1450,24 @@ protected QueryParameters makeQueryParametersForExecution(String hql) {
|
|||||||
optionalId,
|
optionalId,
|
||||||
resultTransformer
|
resultTransformer
|
||||||
);
|
);
|
||||||
queryParameters.setQueryPlan( entityGraphHintedQueryPlan );
|
|
||||||
|
appendQueryPlanToQueryParameters( hql, queryParameters, entityGraphHintedQueryPlan );
|
||||||
|
|
||||||
if ( passDistinctThrough != null ) {
|
if ( passDistinctThrough != null ) {
|
||||||
queryParameters.setPassDistinctThrough( passDistinctThrough );
|
queryParameters.setPassDistinctThrough( passDistinctThrough );
|
||||||
}
|
}
|
||||||
return queryParameters;
|
return queryParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void appendQueryPlanToQueryParameters(
|
||||||
|
String hql,
|
||||||
|
QueryParameters queryParameters,
|
||||||
|
HQLQueryPlan queryPlan) {
|
||||||
|
if ( queryPlan != null ) {
|
||||||
|
queryParameters.setQueryPlan( queryPlan );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public QueryParameters getQueryParameters() {
|
public QueryParameters getQueryParameters() {
|
||||||
final String expandedQuery = getQueryParameterBindings().expandListValuedParameters( getQueryString(), getProducer() );
|
final String expandedQuery = getQueryParameterBindings().expandListValuedParameters( getQueryString(), getProducer() );
|
||||||
return makeQueryParametersForExecution( expandedQuery );
|
return makeQueryParametersForExecution( expandedQuery );
|
||||||
@ -1732,7 +1743,7 @@ public Type determineProperBooleanType(int position, Object value, Type defaultT
|
|||||||
: defaultType;
|
: defaultType;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isSelect() {
|
protected boolean isSelect() {
|
||||||
return getProducer().getFactory().getQueryPlanCache()
|
return getProducer().getFactory().getQueryPlanCache()
|
||||||
.getHQLQueryPlan( getQueryString(), false, Collections.<String, Filter>emptyMap() )
|
.getHQLQueryPlan( getQueryString(), false, Collections.<String, Filter>emptyMap() )
|
||||||
.isSelect();
|
.isSelect();
|
||||||
|
@ -6,8 +6,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.hibernate.query.internal;
|
package org.hibernate.query.internal;
|
||||||
|
|
||||||
|
import org.hibernate.engine.query.spi.HQLQueryPlan;
|
||||||
|
import org.hibernate.engine.query.spi.ReturnMetadata;
|
||||||
|
import org.hibernate.engine.spi.QueryParameters;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.query.ParameterMetadata;
|
|
||||||
import org.hibernate.query.Query;
|
import org.hibernate.query.Query;
|
||||||
import org.hibernate.query.spi.QueryParameterBindings;
|
import org.hibernate.query.spi.QueryParameterBindings;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
@ -18,16 +20,19 @@
|
|||||||
public class QueryImpl<R> extends AbstractProducedQuery<R> implements Query<R> {
|
public class QueryImpl<R> extends AbstractProducedQuery<R> implements Query<R> {
|
||||||
private final String queryString;
|
private final String queryString;
|
||||||
|
|
||||||
|
private final HQLQueryPlan hqlQueryPlan;
|
||||||
|
|
||||||
private final QueryParameterBindingsImpl queryParameterBindings;
|
private final QueryParameterBindingsImpl queryParameterBindings;
|
||||||
|
|
||||||
public QueryImpl(
|
public QueryImpl(
|
||||||
SharedSessionContractImplementor producer,
|
SharedSessionContractImplementor producer,
|
||||||
ParameterMetadata parameterMetadata,
|
HQLQueryPlan hqlQueryPlan,
|
||||||
String queryString) {
|
String queryString) {
|
||||||
super( producer, parameterMetadata );
|
super( producer, hqlQueryPlan.getParameterMetadata() );
|
||||||
|
this.hqlQueryPlan = hqlQueryPlan;
|
||||||
this.queryString = queryString;
|
this.queryString = queryString;
|
||||||
this.queryParameterBindings = QueryParameterBindingsImpl.from(
|
this.queryParameterBindings = QueryParameterBindingsImpl.from(
|
||||||
parameterMetadata,
|
hqlQueryPlan.getParameterMetadata(),
|
||||||
producer.getFactory(),
|
producer.getFactory(),
|
||||||
producer.isQueryParametersValidationEnabled()
|
producer.isQueryParametersValidationEnabled()
|
||||||
);
|
);
|
||||||
@ -43,6 +48,10 @@ public String getQueryString() {
|
|||||||
return queryString;
|
return queryString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public HQLQueryPlan getQueryPlan() {
|
||||||
|
return hqlQueryPlan;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isNativeQuery() {
|
protected boolean isNativeQuery() {
|
||||||
return false;
|
return false;
|
||||||
@ -50,12 +59,14 @@ protected boolean isNativeQuery() {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Type[] getReturnTypes() {
|
public Type[] getReturnTypes() {
|
||||||
return getProducer().getFactory().getReturnTypes( queryString );
|
final ReturnMetadata metadata = hqlQueryPlan.getReturnMetadata();
|
||||||
|
return metadata == null ? null : metadata.getReturnTypes();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] getReturnAliases() {
|
public String[] getReturnAliases() {
|
||||||
return getProducer().getFactory().getReturnAliases( queryString );
|
final ReturnMetadata metadata = hqlQueryPlan.getReturnMetadata();
|
||||||
|
return metadata == null ? null : metadata.getReturnAliases();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -67,4 +78,22 @@ public Query setEntity(int position, Object val) {
|
|||||||
public Query setEntity(String name, Object val) {
|
public Query setEntity(String name, Object val) {
|
||||||
return setParameter( name, val, getProducer().getFactory().getTypeHelper().entity( resolveEntityName( val ) ) );
|
return setParameter( name, val, getProducer().getFactory().getTypeHelper().entity( resolveEntityName( val ) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isSelect() {
|
||||||
|
return hqlQueryPlan.isSelect();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendQueryPlanToQueryParameters(
|
||||||
|
String hql,
|
||||||
|
QueryParameters queryParameters,
|
||||||
|
HQLQueryPlan queryPlan) {
|
||||||
|
if ( queryPlan != null ) {
|
||||||
|
queryParameters.setQueryPlan( queryPlan );
|
||||||
|
}
|
||||||
|
else if ( hql.equals( getQueryString() ) ) {
|
||||||
|
queryParameters.setQueryPlan( getQueryPlan() );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,22 +6,28 @@
|
|||||||
*/
|
*/
|
||||||
package org.hibernate.stat.internal;
|
package org.hibernate.stat.internal;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.GeneratedValue;
|
import javax.persistence.GeneratedValue;
|
||||||
import javax.persistence.Id;
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.LockModeType;
|
||||||
|
import javax.persistence.NamedQuery;
|
||||||
|
import javax.persistence.Tuple;
|
||||||
|
import javax.persistence.TypedQuery;
|
||||||
|
|
||||||
import org.hibernate.SessionFactory;
|
import org.hibernate.SessionFactory;
|
||||||
import org.hibernate.cfg.Environment;
|
import org.hibernate.cfg.Environment;
|
||||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||||
import org.hibernate.stat.QueryStatistics;
|
import org.hibernate.stat.QueryStatistics;
|
||||||
import org.hibernate.stat.Statistics;
|
import org.hibernate.stat.Statistics;
|
||||||
|
|
||||||
import org.hibernate.testing.TestForIssue;
|
import org.hibernate.testing.TestForIssue;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -39,6 +45,7 @@ public Class[] getAnnotatedClasses() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected void addConfigOptions(Map options) {
|
protected void addConfigOptions(Map options) {
|
||||||
options.put( Environment.GENERATE_STATISTICS, "true" );
|
options.put( Environment.GENERATE_STATISTICS, "true" );
|
||||||
}
|
}
|
||||||
@ -63,6 +70,7 @@ protected void afterEntityManagerFactoryBuilt() {
|
|||||||
@Test
|
@Test
|
||||||
public void test() {
|
public void test() {
|
||||||
|
|
||||||
|
statistics.clear();
|
||||||
assertEquals( 0, statistics.getQueryPlanCacheHitCount() );
|
assertEquals( 0, statistics.getQueryPlanCacheHitCount() );
|
||||||
assertEquals( 0, statistics.getQueryPlanCacheMissCount() );
|
assertEquals( 0, statistics.getQueryPlanCacheMissCount() );
|
||||||
|
|
||||||
@ -115,6 +123,165 @@ public void test() {
|
|||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue( jiraKey = "HHH-13077" )
|
||||||
|
public void testCreateQueryHitCount() {
|
||||||
|
statistics.clear();
|
||||||
|
|
||||||
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
|
||||||
|
List<Employee> employees = entityManager.createQuery(
|
||||||
|
"select e from Employee e", Employee.class )
|
||||||
|
.getResultList();
|
||||||
|
|
||||||
|
assertEquals( 5, employees.size() );
|
||||||
|
|
||||||
|
//First time, we get a cache miss, so the query is compiled
|
||||||
|
assertEquals( 1, statistics.getQueryPlanCacheMissCount() );
|
||||||
|
//The hit count should be 0 as we don't need to go to the cache after we already compiled the query
|
||||||
|
assertEquals( 0, statistics.getQueryPlanCacheHitCount() );
|
||||||
|
} );
|
||||||
|
|
||||||
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
|
||||||
|
List<Employee> employees = entityManager.createQuery(
|
||||||
|
"select e from Employee e", Employee.class )
|
||||||
|
.getResultList();
|
||||||
|
|
||||||
|
assertEquals( 5, employees.size() );
|
||||||
|
|
||||||
|
//The miss count is still 1, as no we got the query plan from the cache
|
||||||
|
assertEquals( 1, statistics.getQueryPlanCacheMissCount() );
|
||||||
|
//And the cache hit count increases.
|
||||||
|
assertEquals( 1, statistics.getQueryPlanCacheHitCount() );
|
||||||
|
} );
|
||||||
|
|
||||||
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
|
||||||
|
List<Employee> employees = entityManager.createQuery(
|
||||||
|
"select e from Employee e", Employee.class )
|
||||||
|
.getResultList();
|
||||||
|
|
||||||
|
assertEquals( 5, employees.size() );
|
||||||
|
|
||||||
|
//The miss count is still 1, as no we got the query plan from the cache
|
||||||
|
assertEquals( 1, statistics.getQueryPlanCacheMissCount() );
|
||||||
|
//And the cache hit count increases.
|
||||||
|
assertEquals( 2, statistics.getQueryPlanCacheHitCount() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue( jiraKey = "HHH-13077" )
|
||||||
|
public void testCreateNamedQueryHitCount() {
|
||||||
|
//This is for the NamedQuery that gets compiled
|
||||||
|
assertEquals( 1, statistics.getQueryPlanCacheMissCount() );
|
||||||
|
statistics.clear();
|
||||||
|
|
||||||
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
|
||||||
|
Employee employees = entityManager.createNamedQuery(
|
||||||
|
"find_employee_by_name", Employee.class )
|
||||||
|
.setParameter( "name", "Employee: 1" )
|
||||||
|
.getSingleResult();
|
||||||
|
|
||||||
|
//The miss count is 0 because the plan was compiled when the EMF was built, and we cleared the Statistics
|
||||||
|
assertEquals( 0, statistics.getQueryPlanCacheMissCount() );
|
||||||
|
//The hit count is 1 since we got the plan from the cache
|
||||||
|
assertEquals( 1, statistics.getQueryPlanCacheHitCount() );
|
||||||
|
} );
|
||||||
|
|
||||||
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
|
||||||
|
Employee employees = entityManager.createNamedQuery(
|
||||||
|
"find_employee_by_name", Employee.class )
|
||||||
|
.setParameter( "name", "Employee: 1" )
|
||||||
|
.getSingleResult();
|
||||||
|
|
||||||
|
//The miss count is still 0 because the plan was compiled when the EMF was built, and we cleared the Statistics
|
||||||
|
assertEquals( 0, statistics.getQueryPlanCacheMissCount() );
|
||||||
|
//The hit count is 2 since we got the plan from the cache twice
|
||||||
|
assertEquals( 2, statistics.getQueryPlanCacheHitCount() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue( jiraKey = "HHH-13077" )
|
||||||
|
public void testCreateQueryTupleHitCount() {
|
||||||
|
statistics.clear();
|
||||||
|
|
||||||
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
|
||||||
|
List<Tuple> employees = entityManager.createQuery(
|
||||||
|
"select e.id, e.name from Employee e", Tuple.class )
|
||||||
|
.getResultList();
|
||||||
|
|
||||||
|
assertEquals( 5, employees.size() );
|
||||||
|
|
||||||
|
//First time, we get a cache miss, so the query is compiled
|
||||||
|
assertEquals( 1, statistics.getQueryPlanCacheMissCount() );
|
||||||
|
//The hit count should be 0 as we don't need to go to the cache after we already compiled the query
|
||||||
|
assertEquals( 0, statistics.getQueryPlanCacheHitCount() );
|
||||||
|
} );
|
||||||
|
|
||||||
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
|
||||||
|
List<Tuple> employees = entityManager.createQuery(
|
||||||
|
"select e.id, e.name from Employee e", Tuple.class )
|
||||||
|
.getResultList();
|
||||||
|
|
||||||
|
assertEquals( 5, employees.size() );
|
||||||
|
|
||||||
|
//The miss count is still 1, as no we got the query plan from the cache
|
||||||
|
assertEquals( 1, statistics.getQueryPlanCacheMissCount() );
|
||||||
|
//And the cache hit count increases.
|
||||||
|
assertEquals( 1, statistics.getQueryPlanCacheHitCount() );
|
||||||
|
} );
|
||||||
|
|
||||||
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
|
||||||
|
List<Tuple> employees = entityManager.createQuery(
|
||||||
|
"select e.id, e.name from Employee e", Tuple.class )
|
||||||
|
.getResultList();
|
||||||
|
|
||||||
|
assertEquals( 5, employees.size() );
|
||||||
|
|
||||||
|
//The miss count is still 1, as no we got the query plan from the cache
|
||||||
|
assertEquals( 1, statistics.getQueryPlanCacheMissCount() );
|
||||||
|
//And the cache hit count increases.
|
||||||
|
assertEquals( 2, statistics.getQueryPlanCacheHitCount() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue(jiraKey = "HHH-13077")
|
||||||
|
public void testLockModeHitCount() {
|
||||||
|
statistics.clear();
|
||||||
|
|
||||||
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
TypedQuery<Employee> typedQuery = entityManager.createQuery( "select e from Employee e", Employee.class );
|
||||||
|
|
||||||
|
List<Employee> employees = typedQuery.getResultList();
|
||||||
|
|
||||||
|
assertEquals( 5, employees.size() );
|
||||||
|
|
||||||
|
//First time, we get a cache miss, so the query is compiled
|
||||||
|
assertEquals( 1, statistics.getQueryPlanCacheMissCount() );
|
||||||
|
//The hit count should be 0 as we don't need to go to the cache after we already compiled the query
|
||||||
|
assertEquals( 0, statistics.getQueryPlanCacheHitCount() );
|
||||||
|
|
||||||
|
typedQuery.setLockMode( LockModeType.READ );
|
||||||
|
|
||||||
|
//The hit count should still be 0 as setLockMode() shouldn't trigger a cache hit
|
||||||
|
assertEquals( 0, statistics.getQueryPlanCacheHitCount() );
|
||||||
|
|
||||||
|
assertNotNull( typedQuery.getLockMode() );
|
||||||
|
|
||||||
|
//The hit count should still be 0 as getLockMode() shouldn't trigger a cache hit
|
||||||
|
assertEquals( 0, statistics.getQueryPlanCacheHitCount() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
private void assertQueryStatistics(String hql, int hitCount) {
|
private void assertQueryStatistics(String hql, int hitCount) {
|
||||||
QueryStatistics queryStatistics = statistics.getQueryStatistics( hql );
|
QueryStatistics queryStatistics = statistics.getQueryStatistics( hql );
|
||||||
|
|
||||||
@ -125,6 +292,10 @@ private void assertQueryStatistics(String hql, int hitCount) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Entity(name = "Employee")
|
@Entity(name = "Employee")
|
||||||
|
@NamedQuery(
|
||||||
|
name = "find_employee_by_name",
|
||||||
|
query = "select e from Employee e where e.name = :name"
|
||||||
|
)
|
||||||
public static class Employee {
|
public static class Employee {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
|
Loading…
x
Reference in New Issue
Block a user