Comment utiliser @Cacheable de JPA2 au lieu de @Cache D'Hibernate
Généralement, j'utilise le @Cache D'Hibernate(utilisation = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) {[6] } pour mettre en cache une classe @ Entity, et cela fonctionne bien.
En JPA2, il y a une autre annotation @ Cacheable qui semble être la même fonctionnalité avec le @Cache D'Hibernate. Pour rendre ma classe d'entité indépendante du paquet d'hibernate , je veux essayer. Mais je ne peux pas le faire fonctionner. Chaque fois qu'une simple requête d'id frappe toujours la base de données.
Quelqu'un peut-il me dire où va mal ? Grâce.
Classe d'Entité :
@Entity
//@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@Cacheable(true)
public class User implements Serializable
{
// properties
}
Classe D'essai:
@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 couche" get " hits DB (avec hibernate.show_sql=true).
Persistance.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"/>
Code JPA:
@Override
public T get(Serializable id)
{
return em.find(clazz, id);
}
2 réponses
Selon la spécification JPA 2.0, Si vous voulez mettre en cache sélectivement des entités à l'aide de l'annotation @Cacheable
, Vous êtes censé spécifier un <shared-cache-mode>
dans le persistence.xml
(ou l'équivalent javax.persistence.sharedCache.mode
lors de la création du EntityManagerFactory
).
Ci-dessous, un exemple persistence.xml
avec l'élément et les propriétés pertinents:
<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 HHH-5303 lié à la mise en cache. Donc, ce qui précède n'est pas garanti:)
Références
- Hibernate EntityManager guide de référence
- spécification JPA 2.0
- Section 3.7.1 "L'élément shared-cache-mode"
- Section 11.1.7 "Cachable Annotation"
Pour ceux qui utilisent Spring config au lieu de persistence.xml
, Voici un exemple:
<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 des annotations @Cacheable
, vous ne pouvez utiliser qu'une stratégie de concurrence de cache par défaut, qui est déterminée par la méthode getDefaultAccessType()
de la RegionFactory
. Dans le cas de EhCache, c'est READ_WRITE. Si vous voulez utiliser une autre stratégie, vous devez utiliser les annotations @Cache
D'Hibernate.