7

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

black sensei
  • 6,528
  • 22
  • 109
  • 188
  • I agree it is overkill :) anyway https://stackoverflow.com/a/54774762/175554 is the best details I find so far. I dont think we need entity level @Cacheable at least it work in my machine without it :) – ozkanpakdil Oct 03 '22 at 20:48

0 Answers0