JPA Shared (L2) Entity Cache
Every EntityManagerjakarta.persistence.EntityManagerInterface used to interact with the persistence context. has a persistence context, which is a collection of all the entities that it manages. The persistence context serves as a first-level cache. Retrieving an entity that the EntityManager already manages returns the existing instance from the persistence context, not a newly instantiated one.
The persistence context is scoped to a single EntityManagerjakarta.persistence.EntityManagerInterface used to interact with the persistence context.. This section describes a second-level (L2) cache of entities, which is managed by the EntityManagerFactoryjakarta.persistence.EntityManagerFactoryInterface used to interact with the persistence unit, and to create new instances of EntityManager . and shared by all its EntityManager instances. The broader scope of this cache makes it useful in applications that use many short-term EntityManager instances.
In addition to the EntityManager's L1 cache and the EntityManagerFactory's L2 cache, which are managed on the client side, ObjectDB also manages several server-side caches:
- Cache of database file pages.
- Cache of query programs.
- Cache of query execution results.
The scope of these server-side caches is wider because they exist per database and are shared by all EntityManagerFactory and EntityManager instances for that database, even across different client computers.
This page covers the following topics:
Setting the shared cacheUsing the shared cacheUsing the cache interfaceSetting the shared cache
You can configure the shared (L2) cache at three levels:
- Globally in the ObjectDB configuration.
- Per persistence unit in the
persistence.xmlfile. - Per entity class, using annotations.
ObjectDB Configuration
The shared cache size is specified in the ObjectDB configuration:
<cache ... level2="0mb" />
The level2 attribute determines the size of the EntityManagerFactory's shared cache. The default size, 0, disables the cache. To enable the cache, you must specify a positive value.
Persistence Unit Settings
You can also enable or disable the shared cache by using a persistence unit property:
<persistence-unit name="my-pu"> ... <properties> <property name="jakarta.persistence.sharedCache.mode" value="ALL"/> </properties> ... </persistence-unit>
You can set the jakarta.persistence.sharedCache.mode property to one of the following values:
NONE: The cache is disabled.ENABLE_SELECTIVE: The cache is disabled except for selected entity classes (see below).DISABLE_SELECTIVE: The cache is enabled except for selected entity classes (see below).ALL(the default): The cache is enabled for all entity classes.UNSPECIFIED: Handled differently by JPA providers. In ObjectDB, this value is equivalent toALL, which is the default.
If the cache size is 0, the shared cache is disabled regardless of the mode.
Entity class cache settings
The ENABLE_SELECTIVE mode disables the cache for all entity classes except those explicitly marked as @Cacheablejakarta.persistence.CacheableSpecifies whether an entity should be cached, if caching is enabled, and when the value of the persistence.xml caching element is SharedCacheMode.ENABLE_SELECTIVE or SharedCacheMode.DISABLE_SELECTIVE .. For example:
@Cacheablejakarta.persistence.CacheableSpecifies whether an entity should be cached, if caching is enabled, and when the value of the persistence.xml caching element is SharedCacheMode.ENABLE_SELECTIVE or SharedCacheMode.DISABLE_SELECTIVE . // or @Cacheable(true) @Entityjakarta.persistence.EntityDeclares that the annotated class is an entity. public class MyCacheableEntityClass { ... }
Similarly, the DISABLE_SELECTIVE mode enables the cache for all entity classes except those explicitly marked as not cacheablejakarta.persistence.CacheableSpecifies whether an entity should be cached, if caching is enabled, and when the value of the persistence.xml caching element is SharedCacheMode.ENABLE_SELECTIVE or SharedCacheMode.DISABLE_SELECTIVE .. For example:
@Cacheablejakarta.persistence.CacheableSpecifies whether an entity should be cached, if caching is enabled, and when the value of the persistence.xml caching element is SharedCacheMode.ENABLE_SELECTIVE or SharedCacheMode.DISABLE_SELECTIVE .(false) @Entityjakarta.persistence.EntityDeclares that the annotated class is an entity. public class MyNonCacheableEntityClass extends MyCacheableEntityClass { ... }
@Cacheable is an inherited annotation. An entity class that is not marked with @Cacheable inherits the cacheability setting from its superclass.
Using the shared cache
When enabled, the shared cache automatically provides the following functionality:
- On retrieval: The shared cache is used for entities that are not in the persistence context. If an entity is not in the shared cache, it is retrieved from the database and then added to the shared cache.
- On commit: New and modified entities are added to the shared cache.
JPA provides two properties that you can use to change the default behavior.
jakarta.persistence.cache.retrieveMode
The jakarta.persistence.cache.retrieveMode property specifies whether the shared cache is used on retrieval. This property accepts two values from the CacheRetrieveModejakarta.persistence.CacheRetrieveModeSpecifies how the EntityManager interacts with the second-level cache when data is read from the database via the EntityManager.find methods and execution of queries. enum:
- CacheRetrieveModejakarta.persistence.CacheRetrieveModeSpecifies how the EntityManager interacts with the second-level cache when data is read from the database via the EntityManager.find methods and execution of queries..USEjakarta.persistence.CacheRetrieveMode.USERead entity data from the cache: this is the default behavior.: The cache is used.
- CacheRetrieveModejakarta.persistence.CacheRetrieveModeSpecifies how the EntityManager interacts with the second-level cache when data is read from the database via the EntityManager.find methods and execution of queries..BYPASSjakarta.persistence.CacheRetrieveMode.BYPASSBypass the cache: get data directly from the database.: The cache is not used.
The default setting is USEjakarta.persistence.CacheRetrieveMode.USERead entity data from the cache: this is the default behavior.. You can change it for a specific EntityManager:
em.setPropertyjakarta.persistence.EntityManager.setProperty(String,Object)Set an entity manager property or hint.( "jakarta.persistence.cache.retrieveMode", CacheRetrieveModejakarta.persistence.CacheRetrieveModeSpecifies how the EntityManager interacts with the second-level cache when data is read from the database via the EntityManager.find methods and execution of queries..BYPASSjakarta.persistence.CacheRetrieveMode.BYPASSBypass the cache: get data directly from the database.);
You can also override the setting for a specific retrieval operation:
// Before executing a query: query.setHintjakarta.persistence.TypedQuery.setHint(String,Object)Set a query property or hint.("jakarta.persistence.cache.retrieveMode", CacheRetrieveModejakarta.persistence.CacheRetrieveModeSpecifies how the EntityManager interacts with the second-level cache when data is read from the database via the EntityManager.find methods and execution of queries..BYPASSjakarta.persistence.CacheRetrieveMode.BYPASSBypass the cache: get data directly from the database.); // For retrieval by type and primary key: em.findjakarta.persistence.EntityManager.find(Class,Object,Map)Find by primary key, using the specified properties.(MyEntity2.class, Long.valueOf(1), Collections.<String,Object>singletonMap( "jakarta.persistence.cache.retrieveMode", CacheRetrieveModejakarta.persistence.CacheRetrieveModeSpecifies how the EntityManager interacts with the second-level cache when data is read from the database via the EntityManager.find methods and execution of queries..BYPASSjakarta.persistence.CacheRetrieveMode.BYPASSBypass the cache: get data directly from the database.));
jakarta.persistence.cache.storeMode
The jakarta.persistence.cache.storeMode property specifies whether to add new data to the cache on commit and retrieval. This property accepts three values from the CacheStoreModejakarta.persistence.CacheStoreModeSpecifies how the EntityManager interacts with the second-level cache when data is read from the database and when data is written to the database. enum:
- CacheStoreModejakarta.persistence.CacheStoreModeSpecifies how the EntityManager interacts with the second-level cache when data is read from the database and when data is written to the database..BYPASSjakarta.persistence.CacheStoreMode.BYPASSDon't insert into cache.: The cache is not updated with new data.
- CacheStoreModejakarta.persistence.CacheStoreModeSpecifies how the EntityManager interacts with the second-level cache when data is read from the database and when data is written to the database..USEjakarta.persistence.CacheStoreMode.USEInsert entity data into cache when read from database and insert/update entity data when written to the database: this is the default behavior.: New data is stored in the cache, but only for entities that are not already in the cache.
- CacheStoreModejakarta.persistence.CacheStoreModeSpecifies how the EntityManager interacts with the second-level cache when data is read from the database and when data is written to the database..REFRESHjakarta.persistence.CacheStoreMode.REFRESHInsert/update entity data held in the cache when read from the database and when written to the database.: New data is stored in the cache, which refreshes entities that are already cached.
The default setting is USEjakarta.persistence.CacheStoreMode.USEInsert entity data into cache when read from database and insert/update entity data when written to the database: this is the default behavior.. You can change it for a specific EntityManager:
em.setPropertyjakarta.persistence.EntityManager.setProperty(String,Object)Set an entity manager property or hint.("jakarta.persistence.cache.storeMode", CacheStoreModejakarta.persistence.CacheStoreModeSpecifies how the EntityManager interacts with the second-level cache when data is read from the database and when data is written to the database..BYPASSjakarta.persistence.CacheStoreMode.BYPASSDon't insert into cache.);
You can also override the setting for a specific retrieval operation. For example:
em.findjakarta.persistence.EntityManager.find(Class,Object,Map)Find by primary key, using the specified properties.(MyEntity2.class, Long.valueOf(1), Collections.<String,Object>singletonMap( "jakarta.persistence.cache.storeMode", CacheRetrieveModejakarta.persistence.CacheRetrieveModeSpecifies how the EntityManager interacts with the second-level cache when data is read from the database via the EntityManager.find methods and execution of queries..BYPASSjakarta.persistence.CacheStoreMode.BYPASSDon't insert into cache.));
The difference between CacheStoreMode.USE and CacheStoreMode.REFRESH is apparent when you bypass the cache during retrieval operations. In this case, an entity that is already cached is updated with the freshly retrieved data only when you use CacheStoreMode.REFRESH. This can be useful when other applications or other EntityManagerFactory instances might update the database.
Using the cache interface
The shared cache is represented by the Cachejakarta.persistence.CacheInterface used to interact with the second-level cache. interface. You can get a Cache instance by using the EntityManagerFactoryjakarta.persistence.EntityManagerFactoryInterface used to interact with the persistence unit, and to create new instances of EntityManager .'s getCache()jakarta.persistence.EntityManagerFactory.getCache()Access the cache that is associated with the entity manager factory (the "second level cache"). method:
Cachejakarta.persistence.CacheInterface used to interact with the second-level cache. cache = emf.getCachejakarta.persistence.EntityManagerFactory.getCache()Access the cache that is associated with the entity manager factory (the "second level cache").();
The Cache object lets you check if a specified entity is cached:
boolean isCached = cache.containsjakarta.persistence.Cache.contains(Class,Object)Whether the cache contains data for the given entity.(MyEntity.class, Long.valueOf(id));
You can remove cached entities from the cache by using one of the evict methods:
// Remove a specific entity from the shared cache: cache.evictjakarta.persistence.Cache.evict(Class,Object)Remove the data for the given entity from the cache.(MyEntity.class, Long.valueOf(id)); // Remove all the instances of a specific class from the cache: cache.evictjakarta.persistence.Cache.evict(Class)Remove the data for entities of the specified class (and its subclasses) from the cache.(MyEntity.class); // Clear the shared cache by removing all the cached entities: cache.evictAlljakarta.persistence.Cache.evictAll()Clear the cache.();
In most applications, you do not need to use the Cachejakarta.persistence.CacheInterface used to interact with the second-level cache. interface and its methods directly.