在《Spring使用内存数据库》和《Spring使用内存数据库二》中我们介绍了spring使用内存数据库和JPA进行持久化操作,使用ORM进行持久化操作经常会使用的一个设计概念就是缓存,本文将简单介绍JPA+Hibernate+Ehcache的配置和实现来延伸上两个demo的实现;EclipseLink自带有二级缓存实现而且号称很强大,大家可以试试,当然结合Oracle Coherence就更强大了;OpenJPA号称也很强大,特别是得到IBM的支持后在Websphere应用服务器的实现更强大了,不过不管是Websphere还是TopLink/Coherence都是商业企业产品,都很笨重而且需要Money,还是开源的Better。


首先,配置更新:

public Map jpaProperties() {
        Map props = new HashMap();
        //Hibernate JPA properties
                                                    
        props.put("hibernate.dialect", H2Dialect.class.getName());
        //以下两行指示使用二级缓存
        props.put("hibernate.cache.use_second_level_cache", "true");
        props.put("hibernate.cache.use_query_cache", "true");
        //显示统计数据,这样我们通过输出结果就可以知道缓存命中情况等
        props.put("hibernate.generate_statistics", "true");
        //本文使用Hibernate4,对于以前的版本可以使用如***释代码
        //props.put("hibernate.cache.provider_class", org.hibernate.cache.EhCacheProvider.class.getName());
        props.put("hibernate.cache.region.factory_class", EhCacheRegionFactory.class.getName());      
                                                    
        return props;
    }

其次,在实体类Order和Item中增加缓存标注:

@Entity
@Cacheable
@Cache(region="orders", usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@Table(name="T_ORDER")
public class Order {
//---------------------------------------------
@Entity
@Cacheable
@Cache(region="items", usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Item {

然后,增加ehcache配置文件ehcache.xml



    
    
    
    
    
                          
    
    

最后,修改单元测试用例和Maven依赖:

public void testSaveAndFind() throws Exception {
        for(int i=0; i<1000; i++){
            Order order = new Order();
            Item item = new Item();
            item.setProduct("foo"+i);
            order.getItems().add(item);
            entityManager.persist(order);
        }
                       
        entityManager.flush();
        // Otherwise the query returns the existing order (and we didn't set the
        // parent in the item)...
        entityManager.clear();
                       
        Query query2 = entityManager
                .createQuery(
                        "select o from Order o join o.items i ");
        //query2.setHint("org.hibernate.cacheable", true);
        if(query2 instanceof QueryImpl){
             ((QueryImpl)query2).getHibernateQuery().setCacheable(true);
        }
        assertEquals(1000, query2.getResultList().size());
                       
        query2.getResultList();
        Query query = entityManager
                .createQuery(
                        "select o from Order o join o.items i where i.product=:product")
                .setParameter("product", "foo9");
                       
        query.setHint("org.hibernate.cacheable", true);
                       
        Order other = (Order) query.getSingleResult();
        Order other2 = (Order) query.getSingleResult();
        assertEquals(1, other2.getItems().size());
        assertEquals(other, other2.getItems().iterator().next().getOrder());              
    }

ok,大功告成,可以运行测试用例,然后通过日志查看缓存命中率,也可以修改代码