I am not actually sure whether I am doing everything right but I found it quite an overkill aside using the cache or cacheable annotations on top the domain POJO and setting hibernate.cache.use_query_cache
to true to have to add @QueryHint on JpaRepository query methods before caching starts to work.
To my understanding the declaring the method at interface level is what makes everything so lean so clean with spring-data-jpa.
Unless I add @QueryHints(value = {@QueryHint(name = "org.hibernate.cacheable", value = "true")})
to the Interface below query won't cache
public interface UserRepository extends JpaRepository<User,String> {
@QueryHints(value = {@QueryHint(name = "org.hibernate.cacheable", value = "true")})
User findByEmail(String email);
}
Spring db application config
<?xml version="1.0" encoding="UTF-8"?>
<beans ...">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${h2.jdbc.driverClassName}"/>
<property name="url" value="${h2.jdbc.url}"/>
<property name="username" value="${h2.jdbc.username}"/>
<property name="password" value="${h2.jdbc.password}"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" depends-on="flyway">
<property name="dataSource" ref="dataSource"/>
<property name="persistenceUnitName" value="normal"/>
<property name="packagesToScan" value="net.personal.tutorials.security.domain"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.H2Dialect</prop>
<!--..... -->
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="javax.persistence.sharedCache.mode">ENABLE_SELECTIVE</prop>
</props>
</property>
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
<jpa:repositories base-package="net.personal.tutorials.security.repository"/>
Persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">-->
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="normal" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
</persistence-unit>
</persistence>
ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd"
updateCheck="true"
monitoring="autodetect"
dynamicConfig="true">
<defaultCache maxElementsInMemory="100" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="900" />
<!--<diskStore path="java.io.tmpdir" />-->
<cache name="net.personal.tutorials.security.domain.User"
maxEntriesLocalHeap="10000"
maxEntriesLocalDisk="1000"
eternal="false"
diskSpoolBufferSizeMB="20"
timeToIdleSeconds="300" timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LFU"
transactionalMode="off">
<persistence strategy="localTempSwap" />
</cache>
</ehcache>
net.personal.tutorials.security.domain.User
@Entity
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class User {
@Id
private String Id;
@Column(name = "email", length = 255, unique = true)
private String email;
private String password;
private String comment;
//setters and getters
}
What is the most recommended way of using the second level cache?
thanks