48 votes

Comment utiliser @Cacheable de JPA2 à la place de @Cache d'Hibernate

Généralement , j'utilise Hibernate @Cache(utilisation = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) à cache un @Entité de la classe , et il fonctionne bien.

Dans JPA2 , il y a une autre @Cacheable annotation qui semble être la même fonctionnalité avec Hibernate @Cache. Pour faire ma classe d'entité indépendante de hibernate paquet , j'ai envie de lui donner un essai. Mais je ne peux pas le faire fonctionner. Chaque fois qu'une simple requête id heurte encore à la DB.

Quelqu'un peut-il me dire d'où vient le problème ? Merci.

Classe d'entité :

@Entity
//@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@Cacheable(true) 
public class User implements Serializable
{
 // properties
}

La classe de Test :

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:app.xml"})
@TransactionConfiguration(transactionManager="transactionManager")
public class UserCacheTest
{
  @Inject protected UserDao userDao;

  @Transactional
  @Test
  public void testGet1()
  {
    assertNotNull(userDao.get(2L));
  }

  @Transactional
  @Test
  public void testGet2()
  {
    assertNotNull(userDao.get(2L));
  }

  @Transactional
  @Test
  public void testGet3()
  {
    assertNotNull(userDao.get(2L));
  }
}

Le résultat du test montre chaque "get" hits DB couche (avec mise en veille prolongée.show_sql=true).

Persistence.xml :

<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.use_outer_join" value="true"/>

<property name="hibernate.cache.provider_class" value="org.hibernate.cache.SingletonEhCacheProvider"/>
<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.cache.use_query_cache" value="true"/>

JPA code :

@Override
public T get(Serializable id)
{
  return em.find(clazz, id);
}

46voto

Pascal Thivent Points 295221

Selon la JPA 2.0, si vous souhaitez sélectionner cache des entités à l'aide de l' @Cacheable d'annotation, vous êtes censé indiquer un <shared-cache-mode> dans la persistence.xml (ou l'équivalent) javax.persistence.sharedCache.mode lors de la création de l' EntityManagerFactory).

Ci-dessous, un échantillon persistence.xml avec les éléments pertinents et les propriétés:

<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="FooPu" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    ...
    <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
    <properties>
      ...
      <property name="hibernate.cache.provider_class" value="org.hibernate.cache.SingletonEhCacheProvider"/>
      <property name="hibernate.cache.use_second_level_cache" value="true"/>
      <property name="hibernate.cache.use_query_cache" value="true"/>
    </properties>
  </persistence-unit>
</persistence>

Notez que j'ai vu au moins un problème de HHH-5303 liées à la mise en cache. Ce qui est au dessus n'est pas garanti :)

Références

  • Hibernate EntityManager guide de référence
  • JPA 2.0 Spécification
    • La Section 3.7.1 "shared-cache-mode de l'Élément"
    • Section 11.1.7 "Cachable Annotation"

11voto

John29 Points 285

Pour ceux qui utilisent le Printemps config au lieu de persistence.xml, en voici un échantillon:

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="database" value="MYSQL"/>
            <property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
            <property name="showSql" value="true"/>
            <property name="generateDdl" value="false"/>
        </bean>
    </property>
    <property name="packagesToScan" value="com.mycompany.myproject.domain"/>
    <property name="jpaPropertyMap">
        <map>
            <entry key="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory"/>
            <entry key="hibernate.cache.use_second_level_cache" value="true"/>
            <entry key="hibernate.cache.use_query_cache" value="true"/>
            <entry key="javax.persistence.sharedCache.mode" value="ENABLE_SELECTIVE" />
        </map>
    </property>
</bean>

Notez également que si vous utilisez l' @Cacheable d'annotations, vous pouvez uniquement utiliser un cache par défaut de simultanéité de la stratégie, qui est déterminé par l' getDefaultAccessType() méthode de RegionFactory. En cas de EhCache c'est READ_WRITE. Si vous souhaitez utiliser une autre stratégie, vous devez utiliser Hibernate @Cache des annotations.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X