Second-level Caching
Second level caching in JPA employs a cache between the JPA EntityManager
which has its own (first-level) cache and the database.
Where an entity manager is tied to a specific persistence context and as such, the first-level cache is as well, the second-level cache bridges multiple entity managers to provide a shared cache that further reduces the load on the database.
Application
ApplicationInstance
Enables second-level and query cache within Hibernate using Ehcache.
<options>
<persistence.secondLevelCache/>
</options>
Second-level cache usage
The second-level cache is used whenever an instance of a DataElement is retrieved directly by its identifying property, i.e. its database id.
This can for example be done through the getDetails(DataRef)
method of the
Query cache usage
To make use of the query cache, one must explicitly request a search's results to be cached.
This is done through invoking SearchDetails.setAllowCaching(true)
on the search details of the find action.
Subsequent searches using equal search details (that is: equal finder, values, and options) will then make use of the query cache.
Required manual actions
Apart from enabling this option on the DataElements which should receive the functionality, one must also perform below actions to ensure correct performance and configuration of the second-level cache. Specifically, one must:
- Provide the additional dependencies to the TomEE server
- Provide a configuration for the caches
Additional runtime dependencies
To allow for Ehcache to be used as a second level cache, two dependencies should be included within the CATALINA_HOME/lib
directory:
org.hibernate.hibernate-jcache
(link): Version should match the other hibernate dependencies present inCATALINA_HOME
.org.ehcache.ehcache
(link): Version should be after3.x
, as this includes the jcache support.
The following maven pom file can be used to put these files in the right directory through its initialize
goal:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.normalizedsystems</groupId>
<artifactId>extra-libraries</artifactId>
<!-- Version is not relevant as this pom file is only used to download libraries -->
<version>1.0.0-SNAPSHOT</version>
<properties>
<lib.directory>${CATALINA_HOME}/lib</lib.directory>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>copy-lib</id>
<phase>initialize</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<outputDirectory>${lib.directory}</outputDirectory>
<artifactItems>
<artifactItem>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.9.9</version>
</artifactItem>
<artifactItem>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jcache</artifactId>
<version>5.4.32.Final</version>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Configuration for the cache
Configuration for the created caches can be supplied through an XML file, per Ehcache's documentation.
Note that the second-level caches for each individual DataElement have their alias set to the complete classpath of the element's corresponding Data class.
The query caches have two separate regions set by Hibernate: default-query-results-region
and default-update-timestamps-region
.
Consider the following example of a configuration of the cache for a DataElement City
which is located in the package com.demo
. This example configuration provides a heap cache with 100 entries for each cache with a time to idle of 2 minutes:
<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns='http://www.ehcache.org/v3'
xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd">
<cache alias="com.demo.CityData" uses-template="default"/>
<cache alias="default-update-timestamps-region" uses-template="default">
<expiry/>
</cache>
<cache alias="default-query-results-region" uses-template="default" />
<cache-template name="default">
<key-type>java.lang.Object</key-type>
<value-type>java.lang.Object</value-type>
<expiry>
<tti unit="minutes">2</tti>
</expiry>
<heap unit="entries">100</heap>
</cache-template>
</config>
- The
default-update-timestamps-region
does not contain expiry settings per Hibernate's documentation - Both the key and value types are
java.lang.Object
. This is because different entries are used by Hibernate to manage the first-level cache to the corresponding DataElements. - The queries are cached within a single cache (
default-query-results-region
) and the reserved space is therefore shared between all query results.
The location of this file should then be specified through the hibernate.javax.cache.uri
property within the persistence-unit
defined within the component's persistence.xml
.
As an example, when the above configuration is saved within the data
layer under ext/jpa/resources/META-INF/ehcache.xml
, the following property may be used within persistence.xml
to refer to the configuration:
<property name="hibernate.javax.cache.uri" value="classpath://META-INF/ehcache.xml"/>