2011-03-03 3 views
5

Je suis nouveau en hibernation et au printemps et j'expérimente le cache de second niveau d'hibernation. Mais ça ne marche pas. J'ai une classe de test suivant:Configuration du cache de second niveau d'hibernation

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "classpath:applicationContext.xml" }) 
@TransactionConfiguration 
@Transactional 
public class CacheTest extends AbstractTransactionalJUnit4SpringContextTests 
{ 
    @Test 
     public void testCache1() 
     { 
     System.out.println("Running testCache1"); 
     ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); 
     MutableDAO<AppUser> appUserDAO = new MutableDAOImpl<AppUser>(AppUser.class, (SessionFactory) ctx.getBean("OnMediaSessionFactory"), 10); 
     assertNotNull("AppUser DAO is null.", appUserDAO); 

     SessionFactory sessionFactory = (SessionFactory)ctx.getBean("OnMediaSessionFactory"); 
     long numberOfUsers = appUserDAO.countAll(); 

     System.out.println("Number of rows :" + numberOfUsers); 
     final String cacheRegion = AppUser.class.getCanonicalName(); 

     SecondLevelCacheStatistics settingsStatistics = sessionFactory.getStatistics(). 
      getSecondLevelCacheStatistics(cacheRegion); 
     StopWatch stopWatch = new StopWatch(); 
     stopWatch.start(); 
     appUserDAO.findAll(); 
     stopWatch.stop(); 
     System.out.println("Query time : " + stopWatch.getTotalTimeSeconds()); 
     System.out.println(settingsStatistics); 
    } 

    @Test 
    public void testCache2() 
    { 
     System.out.println("Running testCache2"); 
     ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); 
     MutableDAO<AppUser> appUserDAO = new MutableDAOImpl<AppUser>(AppUser.class, (SessionFactory) ctx.getBean("OnMediaSessionFactory"), 10); 
     assertNotNull("AppUser DAO is null.", appUserDAO); 

     SessionFactory sessionFactory = (SessionFactory)ctx.getBean("OnMediaSessionFactory"); 
     long numberOfUsers = appUserDAO.countAll(); 

     System.out.println("Number of rows :" + numberOfUsers); 
     final String cacheRegion = AppUser.class.getCanonicalName(); 

     SecondLevelCacheStatistics settingsStatistics = sessionFactory.getStatistics(). 
      getSecondLevelCacheStatistics(cacheRegion); 
     StopWatch stopWatch = new StopWatch(); 
     stopWatch.start(); 
     appUserDAO.findAll(); 
     stopWatch.stop(); 
     System.out.println("Query time : " + stopWatch.getTotalTimeSeconds()); 
     System.out.println(settingsStatistics); 
    } 
} 

et j'ai

<prop key="hibernate.show_sql">false</prop> 
<prop key="hibernate.format_sql">true</prop> 
<prop key="hibernate.use_sql_comments">true</prop> 
<prop key="hibernate.cache.use_query_cache">true</prop> 
<prop key="hibernate.cache.use_second_level_cache">true</prop> 
<prop key="hibernate.generate_statistics">true</prop> 
<prop key="hibernate.cache.use_structured_entries">true</prop> 

mais j'obtenir une sortie comme ceci:

Running testCache1 
Number of rows :81 
Query time : 0.129 
SecondLevelCacheStatistics[hitCount=0,missCount=0,putCount=81,elementCountInMemory=81,elementCountOnDisk=0,sizeInMemory=219634] 
Running testCache2 
Number of rows :81 
Query time : 0.063 
SecondLevelCacheStatistics[hitCount=0,missCount=0,putCount=81,elementCountInMemory=81,elementCountOnDisk=0,sizeInMemory=219634] 

ce que je dois faire pour le faire fonctionner?

+0

Les classes d'entités elles-mêmes doivent être explicitement fait cacheable - avez-vous fait cela? – skaffman

+0

oui, j'ai @Cache (usage = CacheConcurrencyStrategy.READ_WRITE) – Daniel

Répondre

3

Votre test semble très étrange, vous créez un nouveau contexte d'application pour chaque test, par conséquent Hibernate SessionFactory ne survit pas entre les tests, ainsi que son cache de second niveau.

essai correct ressemblerait à ceci:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "classpath:applicationContext.xml" }) 
public class CacheTest extends AbstractTransactionalJUnit4SpringContextTests 
{ 
    @Autowired 
    private MutableDAO<AppUser> appUserDAO; 

    @Autowired 
    private SessionFactory sessionFactory; 

    private TransactionTemplate tx; 

    @Autowired 
    public void setPtm(PlatformTransactionManagement ptm) { 
     tx = new TransactionTemplate(ptm); 
    } 

    @Test 
    public void doTestCache() { 
     // Using programmatic transaction management since we need 2 transactions 
     // inside the same method 

     // 1st attempt 
     tx.execute(new TransactionCallbackWithoutResult() { 
      public void doInTransactionWithoutResult(TransactionStatus status) { 
       testCache(); 
      } 
     }); 

     // 2nd attempt 
     tx.execute(new TransactionCallbackWithoutResult() { 
      public void doInTransactionWithoutResult(TransactionStatus status) { 
       testCache(); 
      } 
     }); 

    } 

    public void testCache() { 
     long numberOfUsers = appUserDAO.countAll(); 

     System.out.println("Number of rows :" + numberOfUsers); 
     final String cacheRegion = AppUser.class.getCanonicalName(); 

     SecondLevelCacheStatistics settingsStatistics = sessionFactory.getStatistics(). 
      getSecondLevelCacheStatistics(cacheRegion); 
     StopWatch stopWatch = new StopWatch(); 
     stopWatch.start(); 
     appUserDAO.findAll(); 
     stopWatch.stop(); 
     System.out.println("Query time : " + stopWatch.getTotalTimeSeconds()); 
     System.out.println(settingsStatistics); 
    }  
} 
+0

Merci pour votre réponse. Mais qu'est-ce que @Autowired public void setPtm (PlatformTransactionManagement ptm) { tx = nouveau TransactionTemplate (ptm); } et dans PlatformaticActionManagement? – Daniel

+0

@Daniel: Il est nécessaire pour la gestion des transactions par programme, voir [10.6 Gestion des transactions programmatiques] (http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html#transaction -programmatique). Puisque vous voulez vérifier que les valeurs mises en cache survivent entre les transactions, vous devez exécuter plusieurs transactions dans une méthode de test, et la gestion des transactions par programme est un bon moyen de l'organiser. – axtavt

+0

J'ai exécuté votre code mais maintenant je reçois Nombre de lignes: 81 Heure de la requête: 0.142 SecondLevelCacheStatistics [HitCount = 0, misscount = 0, putCount = 0, elementCountInMemory = 0, elementCountOnDisk = 0, sizeInMemory = 0] Nombre de lignes: 81 temps de requête: 0,031 SecondLevelCacheStatistics [HitCount = 0, misscount = 0, putCount = 0, elementCountInMemory = 0, elementCountOnDisk = 0, tailleInMemory = 0] – Daniel

2

Tout d'abord, rappelez-vous que Hibernate n'utilise pas un fournisseur de cache par défaut. Donc, vous aurez besoin d'un fournisseur de cache "externe" pour le cache 2L de Hibernate. Pour ma réponse, je vais utiliser ehcache et Hibernate 3.3. Notez que la configuration a été modifiée dans les versions plus récentes d'Hibernate, lisez donc les docs pour la version exacte que vous utilisez.

Dans votre configuration Hibernate, vous avez manqué une partie, qui est de pointer Hibernate vers le fournisseur actuel. La propriété hibernate.cache.provider_class fait cela pour Hibernate 3.3. Définir sa valeur à net.sf.ehcache.hibernate.SingletonEhCacheProvider

Maintenant, vous aurez également besoin d'un ehcache.xml, comme ceci:

<?xml version="1.0" encoding="UTF-8"?> 
<ehcache> 

    <diskStore path="./cache" /> 

    <defaultCache maxElementsInMemory="10000" 
        eternal="true" 
        overflowToDisk="true" 
        diskPersistent="true" 
        diskExpiryThreadIntervalSeconds="120" 
        memoryStoreEvictionPolicy="FIFO" /> 

    <cache name="com.mycompany.jpa.MyEntity" 
      maxElementsInMemory="50" 
      overflowToDisk="true" /> 

    <cache name="org.hibernate.cache.StandardQueryCache" 
      maxElementsInMemory="50" 
      overflowToDisk="true" /> 

    <cache name="org.hibernate.cache.UpdateTimestampsCache" 
      maxElementsInMemory="5000" 
      overflowToDisk="true" /> 

</ehcache> 

Vous n'avez pas montrer votre OAC, donc, je ne suis pas sûr qu'il est correct ou non . Notez que vous devez toujours être explicite à propos du cache, car il est destiné à être utilisé pour une solution pour des lieux spécifiques, au lieu d'une solution générique pour tout. Cela signifie que, dans votre DAO, vous ajoutez un indice de requête, indiquant que votre requête peut être mise en cache (à partir de votre test, il semble que vous souhaitiez un cache de requête, pas seulement une mise en cache d'entité).

Si vous ne parvenez toujours pas à le faire fonctionner, veuillez consulter la pièce jointe dans le JIRA suivant. Il contient un projet Maven avec cache activé, donc, vous pourrez peut-être comparer avec votre code:

https://issues.jboss.org/browse/JBPAPP-4224

Questions connexes