5

私はHibernateとSpringに不慣れで、Hibernateの第2レベルのキャッシュを試しています。しかし、それはうまくいかないようです。次のテストクラスがあります。

@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);
     }
}

そして、私が持っています

<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>

しかし、私は次のような出力を取得します:

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]

それを機能させるために私は何をしなければなりませんか?

4

2 に答える 2

3

あなたのテストは非常に奇妙に見えます。テストごとに新しいアプリケーション コンテキストを作成するため、HibernateSessionFactoryはテストとその第 2 レベルのキャッシュの間で存続しません。

正しいテストは次のようになります。

@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);
     }      
 }
于 2011-03-03T14:03:20.507 に答える
2

まず第一に、Hibernate はデフォルトでキャッシュ プロバイダーを使用しないことを覚えておいてください。したがって、Hibernate の 2L キャッシュ用の「外部」キャッシュ プロバイダーが必要になります。私の答えとしては、ehcache と Hibernate 3.3 を使用します。Hibernate の最近のバージョンでは構成が変更されていることに注意してください。使用している正確なバージョンのドキュメントを参照してください。

Hibernate 構成では、Hibernate を実際のプロバイダーにポイントするという 1 つの部分を見逃していました。プロパティhibernate.cache.provider_classは、Hibernate 3.3 に対してそれを行います。その値をに設定しますnet.sf.ehcache.hibernate.SingletonEhCacheProvider

ここで、次のような ehcache.xml も必要になります。

<?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>

あなたはあなたのDAOを見せていないので、それが正しいかどうかはわかりません。キャッシュは、すべての一般的なソリューションではなく、特定の場所のソリューションとして使用されることを意図しているため、常にキャッシュについて明示する必要があることに注意してください。つまり、DAO に、クエリがキャッシュ可能であることを示すクエリ ヒントを追加します (テストから、エンティティ キャッシュだけでなく、クエリ キャッシュが必要なようです)。

それでも動作しない場合は、次の JIRA の添付ファイルを参照してください。キャッシュが有効になっている Maven プロジェクトが含まれているため、コードと比較できる場合があります。

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

于 2011-03-03T14:03:45.110 に答える