En règle générale, j'utilise @ Cache (utilisation = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) d'Hibernate pour mettre en cache une classe @Entity, et cela fonctionne bien.
Dans JPA2, il existe une autre annotation @Cacheable qui semble être la même fonctionnalité que @Cache d'Hibernate. Pour rendre ma classe d'entité indépendante du package de hibernate, je veux l'essayer. Mais je ne peux pas le faire fonctionner. Chaque fois, une simple requête d'ID frappe toujours la base de données.
Quelqu'un peut-il me dire où va mal? Merci.
Classe d'entité:
@Entity
//@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@Cacheable(true)
public class User implements Serializable
{
// properties
}
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 couche de base de données "get" hits (avec hibernate.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"/>
Code JPA:
@Override
public T get(Serializable id)
{
return em.find(clazz, id);
}
Selon la spécification JPA 2.0, si vous souhaitez mettre en cache de manière sélective des entités à l'aide de @Cacheable
annotation, 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 approprié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 HHH-53 lié à la mise en cache. Donc, ce qui précède n'est pas garanti :)
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 par défaut du cache, qui est déterminée par la méthode getDefaultAccessType()
de RegionFactory
. Dans le cas d'EhCache, c'est READ_WRITE . Si vous souhaitez utiliser une autre stratégie, vous devez utiliser les annotations @Cache
D'Hibernate.