You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@openjpa.apache.org by Adrian Gonzalez <ad...@yahoo.fr> on 2013/01/23 10:38:41 UTC

Portable way to use query cache

Hello,

I'm a newbie with openJPA, I would like to know what's the best way to do query caching (in a JPA 2.x portable way).
My webapp will run on JBoss 7.x (Hibernate) and Websphere 8 (OpenJPA).


From , [1] there's some proprietary API involved.

Is there a portable way, i.e. using hints instead [2]?

Thanks !

[1] http://openjpa.apache.org/builds/2.0.1/apache-openjpa-2.0.1/docs/manual/main.html
OpenJPAEntityManagerFactory oemf = OpenJPAPersistence.cast(emf);
QueryResultCache qcache = oemf.getQueryResultCache();

[2] entityManager.createNamedQuery(
NamedQueries.ETAT_CONTRAT_FIND_ALL, EtatContrat.class).setHint("openjpa.querycache", true);

Re: Portable way to use query cache

Posted by Adrian Gonzalez <ad...@yahoo.fr>.
Created https://issues.apache.org/jira/browse/OPENJPA-2327 to track this.

Regards,

Adrian

Re: Portable way to use query cache

Posted by Adrian Gonzalez <ad...@yahoo.fr>.
Ok, just implemented second approach (build on top of first one) - tested it with Hibernate 4.x.

You'll just have to set query hint "javax.persistence.cache.retrieveMode" to USE :
public List<Civilite> findAllCivilite() {
return entityManager
.createNamedQuery(NamedQueries.CIVILITE_FIND_ALL,
Civilite.class)
.setHint("javax.persistence.cache.retrieveMode", CacheRetrieveMode.USE)
.getResultList();
}

And use an em produced / decorated like that :
public class EntityManagerConfigProducer {

@PersistenceContext
private EntityManager entityManager;

@Produces
public EntityManager getEntityManager() {
return new PortableEntityManager(entityManager);
}
}

Regards,

Adrian

P.S. Here's the code I've used for this :

=== PortableEntityManager.java (don't like the name :( )

public class PortableEntityManager extends DelegatingEntityManager {
private static final String RETRIEVE_MODE = "javax.persistence.cache.retrieveMode";
private static final String STORE_MODE = "javax.persistence.cache.storeMode";

public PortableEntityManager(EntityManager em) {
super(em);
}

@Override
public Query createQuery(String qlString) {
return new CacheSupportQuery(getDelegate().createQuery(qlString));
}

@Override
public <T> TypedQuery<T> createQuery(CriteriaQuery<T> criteriaQuery) {
return new CacheSupportTypedQuery<T>(getDelegate().createQuery(criteriaQuery));
}

@Override
public <T> TypedQuery<T> createQuery(String qlString, Class<T> resultClass) {
return new CacheSupportTypedQuery<T>(getDelegate().createQuery(qlString, resultClass));
}

@Override
public Query createNamedQuery(String name) {
return new CacheSupportQuery(getDelegate().createNamedQuery(name));
}

@Override
public <T> TypedQuery<T> createNamedQuery(String name, Class<T> resultClass) {
return new CacheSupportTypedQuery<T>(getDelegate().createNamedQuery(name, resultClass));
}

@Override
public Query createNativeQuery(String sqlString) {
return new CacheSupportQuery(getDelegate().createNativeQuery(sqlString));
}

@Override
public Query createNativeQuery(String sqlString, @SuppressWarnings("rawtypes") Class resultClass) {
return new CacheSupportQuery(getDelegate().createNativeQuery(sqlString,
resultClass));
}

@Override
public Query createNativeQuery(String sqlString, String resultSetMapping) {
return new CacheSupportQuery(getDelegate().createNativeQuery(sqlString,
resultSetMapping));
}

public static class CacheSupportTypedQuery<X> extends DelegatingTypedQuery<X> {

public CacheSupportTypedQuery(TypedQuery<X> query) {
super(query);
}

@Override
public TypedQuery<X> setHint(String hintName, Object value) {
return portableQueryHint(hintName, value, this);
}
}

public static class CacheSupportQuery extends DelegatingQuery {

public CacheSupportQuery(Query query) {
super(query);
}

@Override
public Query setHint(String hintName, Object value) {
return portableQueryHint(hintName, value, this);
}
}
private static <Q extends DelegatingQuery> Q portableQueryHint(String hintName, Object value, Q query) {
Object retrievalMode = null;
Object storeMode = null;
boolean cacheHint = false;
if (RETRIEVE_MODE.equals(hintName)) {
retrievalMode = value;
storeMode = (query.getHints() != null ? query.getHints().get(STORE_MODE) : null);
cacheHint = true;
} else if (STORE_MODE.equals(hintName)) {
retrievalMode = (query.getHints() != null ? query.getHints().get(RETRIEVE_MODE) : null);
storeMode = value;
cacheHint = true;
}
if (cacheHint) {
if ((storeMode != null && !storeMode
.equals(CacheStoreMode.BYPASS))
|| (retrievalMode != null && !retrievalMode
.equals(CacheStoreMode.BYPASS))) {
JpaUtils.cacheQuery(query.getDelegate(), true);
} else {
JpaUtils.cacheQuery(query.getDelegate(), false);
}
}
query.getDelegate().setHint(hintName, value);
return query;
}
}


=== DelegatingEntityManager.java

public class DelegatingEntityManager implements EntityManager {

private EntityManager em;
public DelegatingEntityManager(EntityManager em) {
this.em = em;
}

@Override
public void persist(Object entity) {
em.persist(entity);
}

@Override
public <T> T merge(T entity) {
return em.merge(entity);
}

@Override
public void remove(Object entity) {
em.remove(entity);
}

@Override
public <T> T find(Class<T> entityClass, Object primaryKey) {
return em.find(entityClass, primaryKey);
}

@Override
public <T> T find(Class<T> entityClass, Object primaryKey,
Map<String, Object> properties) {
return em.find(entityClass, primaryKey, properties);
}

@Override
public <T> T find(Class<T> entityClass, Object primaryKey,
LockModeType lockMode) {
return em.find(entityClass, primaryKey, lockMode);
}

@Override
public <T> T find(Class<T> entityClass, Object primaryKey,
LockModeType lockMode, Map<String, Object> properties) {
return em.find(entityClass, primaryKey, lockMode, properties);
}

@Override
public <T> T getReference(Class<T> entityClass, Object primaryKey) {
return em.getReference(entityClass, primaryKey);
}

@Override
public void flush() {
em.flush();
}

@Override
public void setFlushMode(FlushModeType flushMode) {
em.setFlushMode(flushMode);
}

@Override
public FlushModeType getFlushMode() {
return em.getFlushMode();
}

@Override
public void lock(Object entity, LockModeType lockMode) {
em.lock(entity, lockMode);
}

@Override
public void lock(Object entity, LockModeType lockMode,
Map<String, Object> properties) {
em.lock(entity, lockMode, properties);
}

@Override
public void refresh(Object entity) {
em.refresh(entity);
}

@Override
public void refresh(Object entity, Map<String, Object> properties) {
em.refresh(entity, properties);
}

@Override
public void refresh(Object entity, LockModeType lockMode) {
em.refresh(entity, lockMode);
}

@Override
public void refresh(Object entity, LockModeType lockMode,
Map<String, Object> properties) {
em.refresh(entity, lockMode, properties);
}

@Override
public void clear() {
em.clear();
}

@Override
public void detach(Object entity) {
em.detach(entity);
}

@Override
public boolean contains(Object entity) {
return em.contains(entity);
}

@Override
public LockModeType getLockMode(Object entity) {
return em.getLockMode(entity);
}

@Override
public void setProperty(String propertyName, Object value) {
em.setProperty(propertyName, value);
}

@Override
public Map<String, Object> getProperties() {
return em.getProperties();
}

@Override
public Query createQuery(String qlString) {
return em.createQuery(qlString);
}

@Override
public <T> TypedQuery<T> createQuery(CriteriaQuery<T> criteriaQuery) {
return em.createQuery(criteriaQuery);
}

@Override
public <T> TypedQuery<T> createQuery(String qlString, Class<T> resultClass) {
return em.createQuery(qlString, resultClass);
}

@Override
public Query createNamedQuery(String name) {
return em.createNamedQuery(name);
}

@Override
public <T> TypedQuery<T> createNamedQuery(String name, Class<T> resultClass) {
return em.createNamedQuery(name, resultClass);
}

@Override
public Query createNativeQuery(String sqlString) {
return em.createNativeQuery(sqlString);
}

@Override
public Query createNativeQuery(String sqlString, @SuppressWarnings("rawtypes") Class resultClass) {
return em.createNativeQuery(sqlString, resultClass);
}

@Override
public Query createNativeQuery(String sqlString, String resultSetMapping) {
return em.createNativeQuery(sqlString, resultSetMapping);
}

@Override
public void joinTransaction() {
em.joinTransaction();
}

@Override
public <T> T unwrap(Class<T> cls) {
return em.unwrap(cls);
}

@Override
public EntityManager getDelegate() {
return em;
}

@Override
public void close() {
em.close();
}

@Override
public boolean isOpen() {
return em.isOpen();
}

@Override
public EntityTransaction getTransaction() {
return em.getTransaction();
}

@Override
public EntityManagerFactory getEntityManagerFactory() {
return em.getEntityManagerFactory();
}

@Override
public CriteriaBuilder getCriteriaBuilder() {
return em.getCriteriaBuilder();
}

@Override
public Metamodel getMetamodel() {
return em.getMetamodel();
}
}


=== DelegatingQuery.java

public class DelegatingQuery implements Query {
private Query delegate;
public DelegatingQuery(Query delegate) {
this.delegate = delegate;
}
public Query getDelegate() {
return delegate;
}

@SuppressWarnings("rawtypes")
public List getResultList() {
return delegate.getResultList();
}

public Object getSingleResult() {
return delegate.getSingleResult();
}

public int executeUpdate() {
return delegate.executeUpdate();
}

public Query setMaxResults(int maxResult) {
return delegate.setMaxResults(maxResult);
}

public int getMaxResults() {
return delegate.getMaxResults();
}

public Query setFirstResult(int startPosition) {
return delegate.setFirstResult(startPosition);
}

public int getFirstResult() {
return delegate.getFirstResult();
}

public Query setHint(String hintName, Object value) {
return delegate.setHint(hintName, value);
}

public Map<String, Object> getHints() {
return delegate.getHints();
}

public <T> Query setParameter(Parameter<T> param, T value) {
return delegate.setParameter(param, value);
}

public Query setParameter(Parameter<Calendar> param, Calendar value,
TemporalType temporalType) {
return delegate.setParameter(param, value, temporalType);
}

public Query setParameter(Parameter<Date> param, Date value,
TemporalType temporalType) {
return delegate.setParameter(param, value, temporalType);
}

public Query setParameter(String name, Object value) {
return delegate.setParameter(name, value);
}

public Query setParameter(String name, Calendar value,
TemporalType temporalType) {
return delegate.setParameter(name, value, temporalType);
}

public Query setParameter(String name, Date value, TemporalType temporalType) {
return delegate.setParameter(name, value, temporalType);
}

public Query setParameter(int position, Object value) {
return delegate.setParameter(position, value);
}

public Query setParameter(int position, Calendar value,
TemporalType temporalType) {
return delegate.setParameter(position, value, temporalType);
}

public Query setParameter(int position, Date value,
TemporalType temporalType) {
return delegate.setParameter(position, value, temporalType);
}

public Set<Parameter<?>> getParameters() {
return delegate.getParameters();
}

public Parameter<?> getParameter(String name) {
return delegate.getParameter(name);
}

public <T> Parameter<T> getParameter(String name, Class<T> type) {
return delegate.getParameter(name, type);
}

public Parameter<?> getParameter(int position) {
return delegate.getParameter(position);
}

public <T> Parameter<T> getParameter(int position, Class<T> type) {
return delegate.getParameter(position, type);
}

public boolean isBound(Parameter<?> param) {
return delegate.isBound(param);
}

public <T> T getParameterValue(Parameter<T> param) {
return delegate.getParameterValue(param);
}

public Object getParameterValue(String name) {
return delegate.getParameterValue(name);
}

public Object getParameterValue(int position) {
return delegate.getParameterValue(position);
}

public Query setFlushMode(FlushModeType flushMode) {
return delegate.setFlushMode(flushMode);
}

public FlushModeType getFlushMode() {
return delegate.getFlushMode();
}

public Query setLockMode(LockModeType lockMode) {
return delegate.setLockMode(lockMode);
}

public LockModeType getLockMode() {
return delegate.getLockMode();
}

public <T> T unwrap(Class<T> cls) {
return delegate.unwrap(cls);
}
}


=== DelegatingTypedQuery.java

public class DelegatingTypedQuery<X> extends DelegatingQuery implements TypedQuery<X> {

public DelegatingTypedQuery(TypedQuery<X> delegate) {
super(delegate);
}
@SuppressWarnings("unchecked")
public TypedQuery<X> getDelegate() {
return (TypedQuery<X>) super.getDelegate();
}

@Override
public List<X> getResultList() {
return getDelegate().getResultList();
}

@Override
public X getSingleResult() {
return getDelegate().getSingleResult();
}

@Override
public TypedQuery<X> setMaxResults(int maxResult) {
return getDelegate().setMaxResults(maxResult);
}

@Override
public int executeUpdate() {
return getDelegate().executeUpdate();
}

@Override
public TypedQuery<X> setFirstResult(int startPosition) {
return getDelegate().setFirstResult(startPosition);
}

@Override
public TypedQuery<X> setHint(String hintName, Object value) {
return getDelegate().setHint(hintName, value);
}

@Override
public int getMaxResults() {
return getDelegate().getMaxResults();
}

@Override
public <T> TypedQuery<X> setParameter(Parameter<T> param, T value) {
return getDelegate().setParameter(param, value);
}

@Override
public int getFirstResult() {
return getDelegate().getFirstResult();
}

@Override
public TypedQuery<X> setParameter(Parameter<Calendar> param,
Calendar value, TemporalType temporalType) {
return getDelegate().setParameter(param, value, temporalType);
}

@Override
public TypedQuery<X> setParameter(Parameter<Date> param, Date value,
TemporalType temporalType) {
return getDelegate().setParameter(param, value, temporalType);
}

@Override
public Map<String, Object> getHints() {
return getDelegate().getHints();
}

@Override
public TypedQuery<X> setParameter(String name, Object value) {
return getDelegate().setParameter(name, value);
}

@Override
public TypedQuery<X> setParameter(String name, Calendar value,
TemporalType temporalType) {
return getDelegate().setParameter(name, value, temporalType);
}

@Override
public TypedQuery<X> setParameter(String name, Date value,
TemporalType temporalType) {
return getDelegate().setParameter(name, value, temporalType);
}

@Override
public TypedQuery<X> setParameter(int position, Object value) {
return getDelegate().setParameter(position, value);
}

@Override
public TypedQuery<X> setParameter(int position, Calendar value,
TemporalType temporalType) {
return getDelegate().setParameter(position, value, temporalType);
}

@Override
public TypedQuery<X> setParameter(int position, Date value,
TemporalType temporalType) {
return getDelegate().setParameter(position, value, temporalType);
}

@Override
public TypedQuery<X> setFlushMode(FlushModeType flushMode) {
return getDelegate().setFlushMode(flushMode);
}

@Override
public TypedQuery<X> setLockMode(LockModeType lockMode) {
return getDelegate().setLockMode(lockMode);
}

@Override
public Set<Parameter<?>> getParameters() {
return getDelegate().getParameters();
}

@Override
public Parameter<?> getParameter(String name) {
return getDelegate().getParameter(name);
}

@Override
public <T> Parameter<T> getParameter(String name, Class<T> type) {
return getDelegate().getParameter(name, type);
}

@Override
public Parameter<?> getParameter(int position) {
return getDelegate().getParameter(position);
}

@Override
public <T> Parameter<T> getParameter(int position, Class<T> type) {
return getDelegate().getParameter(position, type);
}

@Override
public boolean isBound(Parameter<?> param) {
return getDelegate().isBound(param);
}

@Override
public <T> T getParameterValue(Parameter<T> param) {
return getDelegate().getParameterValue(param);
}

@Override
public Object getParameterValue(String name) {
return getDelegate().getParameterValue(name);
}

@Override
public Object getParameterValue(int position) {
return getDelegate().getParameterValue(position);
}

@Override
public FlushModeType getFlushMode() {
return getDelegate().getFlushMode();
}

@Override
public LockModeType getLockMode() {
return getDelegate().getLockMode();
}

@Override
public <T> T unwrap(Class<T> cls) {
return getDelegate().unwrap(cls);
}
}

----- Mail original -----
De : Adrian Gonzalez <ad...@yahoo.fr>
À : "users@openjpa.apache.org" <us...@openjpa.apache.org>
Cc : 
Envoyé le : Mercredi 23 janvier 2013 14h21
Objet : Re: Portable way to use query cache



1. After looking a little bit, I don't think we can use hint for query caching in OpenJPA.
If this is confirmed, I'll open a JIRA for this.


2. Meanwhile, I've created this little utility [1] to do enable portable query caching.

I've tested it only with Hibernate for the moment, but it should work with OpenJPA and toplink.

To use it, just do :

JpaUtils.cacheQuery(entityManager.createNamedQuery("myNamedQuery", Civilite.class)).getResultList();


3. Perhaps there's a better approach - using a decorating entityManager, which decorates the query and intercepts setHint calls and call the appropriate API whenever the hint is "query.cache" (or sthing like that) :
Then you'll just have to do :
entityManager.createNamedQuery("myNamedQuery", Civilite.class).setHint("query.cache").getResultList(); 


With a CDI producer - or equivalent doing :

@PersistenceContext
private EntityManager em;

@Produces
public EntityManager getEntityManager () {
  return new EntityManagerDecorator(em);
}

WDYT ?

[1] JpaUtils code :
public final class JpaUtils {
public static <X extends Query> X cacheQuery(X query) {
return cacheQuery(query, true);
}
public static <X extends Query> X cacheQuery(X query, boolean cache) {
String queryClassname = query.getClass().getName(); 
if (queryClassname.startsWith("org.hibernate")) {
query.setHint("org.hibernate.cacheable", cache);
} else if (queryClassname.startsWith("org.apache.openjpa")) {
OpenJPAEntityManager oem = ((OpenJPAQuery<?>) query).getEntityManager();
OpenJPAEntityManagerFactory oemf = oem.getEntityManagerFactory();
QueryResultCache qcache = oemf.getQueryResultCache();
if (cache == true) {
qcache.pin(query);
} else {
qcache.unpin(query);
}
} else if (queryClassname.startsWith("org.eclipse.persistence")) {
query.setHint("eclipselink.query-results-cache", true);
}
return query;
}
}

----- Mail original -----
De : Adrian Gonzalez <ad...@yahoo.fr>
À : "users@openjpa.apache.org" <us...@openjpa.apache.org>
Cc : 
Envoyé le : Mercredi 23 janvier 2013 10h38
Objet : Portable way to use query cache

Hello,

I'm a newbie with openJPA, I would like to know what's the best way to do query caching (in a JPA 2.x portable way).
My webapp will run on JBoss 7.x (Hibernate) and Websphere 8 (OpenJPA).


From , [1] there's some proprietary API involved.

Is there a portable way, i.e. using hints instead [2]?

Thanks !

[1] http://openjpa.apache.org/builds/2.0.1/apache-openjpa-2.0.1/docs/manual/main.html
OpenJPAEntityManagerFactory oemf = OpenJPAPersistence.cast(emf);
QueryResultCache qcache = oemf.getQueryResultCache();

[2] entityManager.createNamedQuery(
NamedQueries.ETAT_CONTRAT_FIND_ALL, EtatContrat.class).setHint("openjpa.querycache", true);

Re: Portable way to use query cache

Posted by Adrian Gonzalez <ad...@yahoo.fr>.

1. After looking a little bit, I don't think we can use hint for query caching in OpenJPA.
If this is confirmed, I'll open a JIRA for this.


2. Meanwhile, I've created this little utility [1] to do enable portable query caching.

I've tested it only with Hibernate for the moment, but it should work with OpenJPA and toplink.

To use it, just do :

JpaUtils.cacheQuery(entityManager.createNamedQuery("myNamedQuery", Civilite.class)).getResultList();


3. Perhaps there's a better approach - using a decorating entityManager, which decorates the query and intercepts setHint calls and call the appropriate API whenever the hint is "query.cache" (or sthing like that) :
Then you'll just have to do :
entityManager.createNamedQuery("myNamedQuery", Civilite.class).setHint("query.cache").getResultList(); 


With a CDI producer - or equivalent doing :

@PersistenceContext
private EntityManager em;

@Produces
public EntityManager getEntityManager () {
  return new EntityManagerDecorator(em);
}

WDYT ?

[1] JpaUtils code :
public final class JpaUtils {
public static <X extends Query> X cacheQuery(X query) {
return cacheQuery(query, true);
}
public static <X extends Query> X cacheQuery(X query, boolean cache) {
String queryClassname = query.getClass().getName(); 
if (queryClassname.startsWith("org.hibernate")) {
query.setHint("org.hibernate.cacheable", cache);
} else if (queryClassname.startsWith("org.apache.openjpa")) {
OpenJPAEntityManager oem = ((OpenJPAQuery<?>) query).getEntityManager();
OpenJPAEntityManagerFactory oemf = oem.getEntityManagerFactory();
QueryResultCache qcache = oemf.getQueryResultCache();
if (cache == true) {
qcache.pin(query);
} else {
qcache.unpin(query);
}
} else if (queryClassname.startsWith("org.eclipse.persistence")) {
query.setHint("eclipselink.query-results-cache", true);
}
return query;
}
}

----- Mail original -----
De : Adrian Gonzalez <ad...@yahoo.fr>
À : "users@openjpa.apache.org" <us...@openjpa.apache.org>
Cc : 
Envoyé le : Mercredi 23 janvier 2013 10h38
Objet : Portable way to use query cache

Hello,

I'm a newbie with openJPA, I would like to know what's the best way to do query caching (in a JPA 2.x portable way).
My webapp will run on JBoss 7.x (Hibernate) and Websphere 8 (OpenJPA).


From , [1] there's some proprietary API involved.

Is there a portable way, i.e. using hints instead [2]?

Thanks !

[1] http://openjpa.apache.org/builds/2.0.1/apache-openjpa-2.0.1/docs/manual/main.html
OpenJPAEntityManagerFactory oemf = OpenJPAPersistence.cast(emf);
QueryResultCache qcache = oemf.getQueryResultCache();

[2] entityManager.createNamedQuery(
NamedQueries.ETAT_CONTRAT_FIND_ALL, EtatContrat.class).setHint("openjpa.querycache", true);


Re: Portable way to use query cache

Posted by Adrian Gonzalez <ad...@yahoo.fr>.
Thanks for the link.

I didn't catch the following line first time i read it : 
Caching is not used when the data cache does not have any cached data for an id in a query result. 


So in Open JPA, query cache is active if all resulting entities from thje query are themselves cacheable (i.e. annotated with @Cacheable).
This makes a cacheable query hint unnecessary with OpenJPA then.

Thanks once more for the clarification and sorry for the noise.

----- Mail original -----
De : Jesse Farinacci <ji...@gmail.com>
À : users@openjpa.apache.org; Adrian Gonzalez <ad...@yahoo.fr>
Cc : 
Envoyé le : Mercredi 23 janvier 2013 15h51
Objet : Re: Portable way to use query cache

Greetings,

On Wed, Jan 23, 2013 at 4:38 AM, Adrian Gonzalez <ad...@yahoo.fr> wrote:
> I'm a newbie with openJPA, I would like to know what's the best way to do query caching (in a JPA 2.x portable way).
> My webapp will run on JBoss 7.x (Hibernate) and Websphere 8 (OpenJPA).

http://openjpa.apache.org/builds/2.2.1/apache-openjpa/docs/ref_guide_caching.html

-Jesse

-- 
There are 10 types of people in this world, those
that can read binary and those that can not.


Re: Portable way to use query cache

Posted by Jesse Farinacci <ji...@gmail.com>.
Greetings,

On Wed, Jan 23, 2013 at 4:38 AM, Adrian Gonzalez <ad...@yahoo.fr> wrote:
> I'm a newbie with openJPA, I would like to know what's the best way to do query caching (in a JPA 2.x portable way).
> My webapp will run on JBoss 7.x (Hibernate) and Websphere 8 (OpenJPA).

http://openjpa.apache.org/builds/2.2.1/apache-openjpa/docs/ref_guide_caching.html

-Jesse

-- 
There are 10 types of people in this world, those
that can read binary and those that can not.