Friday, February 10, 2012

JPA Caching in EclipseLink 2.3.2


Best Practice in JPA series:
Part 1 – JPA Caching in EclipseLink
Part 2 – One-to-one relationship using EclipseLink


Java Persistence API 2.0 defines Level 1 (L1) Cache (Entity Cache), Level 2 (L2) Cache (Shared Entity Cache) and Query (Result) Cache. Now I can take full advantage of JPA cache, just like what I did 5, 6 years ago using Hibernate cache. Although Hibernate also has its JPA implementation, I found EclipseLink has better default settings and also easier to enable advanced features. Here are some random tips.

The shared attribute of @Cache annotation has deprecated and is replaced by isolation=CacheIsolationType.SHARED, which means sharing entity cache between EntityManager objects and allowing query cache (if enabled) to use entity cache. Even you don't set @Cache annotation on a domain object, it's enabled by default.

CacheIsolationType.PROTECTED means sharing entity cache between EntityManager objects but disallowing query cache to use entity cache, even when query cache is enabled.

CacheIsolationType.ISOLATED means not sharing entity cache between EntityManager objects and disallow query cache to use entity cache, even when query cache is enabled.

The default coordinationType=CacheCoordinationType.SEND_OBJECT_CHANGES in @Cache means any entity update to database also updates entity in cache, which is great in performance.

Set hints = { @QueryHint(name = QueryHints.QUERY_RESULTS_CACHE, value = HintValues.TRUE) } in @NamedQuery if you want to enable query cache. But unless you have a fixed domain objects, don't enable its query cache. Note that "eclipselink.query-results-cache" is not a standard JPA hint, you cannot set it to "True" for a javax.persistence.Query object.

Unless you have every domain object in entity cache, don't use hints = { @QueryHint(name = QueryHints.CACHE_USAGE, value = CacheUsage.CheckCacheOnly) } in @NamedQuery.

Set <property name="eclipselink.logging.level" value="FINE" /> in META-INFO/persistence.xml to show SQL statements.

Unless you want to change the default cache retrieve / store mode, don't need to set following properties to EntityManager object.
em.setProperty(QueryHints.CACHE_RETRIEVE_MODE, CacheRetrieveMode.USE);
em.setProperty(QueryHints.CACHE_STORE_MODE, CacheStoreMode.USE);

Even you don't set any hint in @NamedQuery, query result will be used to populate entity cache.

Only entityManager.find(entityClass, id) can use entity cache. Get entity, or get entities, by any field(s) other than id don't use entity cache.

The default sizes of entity cache and query cache are 100 each.

If you get
Exception in thread "main" java.lang.IllegalArgumentException: An exception occurred while creating a query in EntityManager:
Exception Description: Syntax error parsing the query [from Entity], line 1, column 0: unexpected token [from].
Internal Exception: NoViableAltException(33@[])
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1477)
change your JPA query to entityManager.createQuery("select entity from Entity entity").getResultList();

Please feel free to let me know if you have any questions regarding EclipseLink cache.

No comments:

Post a Comment