zoukankan      html  css  js  c++  java
  • 简单聊聊Ehcache缓存

    最近工作没有那么忙,有时间来写写东西。今年的系统分析师报名已经开始了,面对历年的真题,真的难以入笔,所以突然对未来充满了担忧,还是得抓紧时间学习技术。

    同事推了一篇软文,看到了这个Ehcache,感觉简单又好用,所以在自己这边也做个记录。

    先来谈谈什么是Ehcache缓存,我们从实际场景出发,支撑一个系统最直接的东西就是数据库,针对数据库我们最常用的操作就是查询。反复的查询数据库会导致数据库压力变大,传统的数据库查询效率就不高(网络、sql语句复杂),导致查询体验不好。尤其当我们查询的语句还是类似甚至重复的时候,这就是浪费资源了。那这个时候,缓存机制就变得很有必要了。像我们经常使用的实现缓存的方式大致有两种,一种是NoSQL数据库,比如Redis、MongoDB等,另一种便是今天要提的缓存框架:Ehcache、Memcache等。

    引用官方的内容一句话定义:EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider。

    下面就开始使用了:

    整合Ehcache-优化性能-降低查询数据库的频率
    Spring集成Ehcache:
    配置Ehcache缓存管理器(EhcacheManager),将其注入给Spring平台缓存管理器(cachemanager),Spring平台缓存管理器再注入给Spring缓存注解驱动。代码中使用注解进行缓存。
     
    Shiro集成Ehcache:
    配置Ehcache缓存管理器(EhcacheManager),将其注入给Shiro缓存管理器(这里是shiro整合ehcache的缓存管理器),最后将Shiro的缓存管理器注入给Shiro安全管理器
    1.通过maven坐标导入jar(ehcache和spring的context-support)
     
    <ehcache.version>2.6.10</ehcache.version>
    <dependency>
        <groupId>net.sf.ehcache</groupId>
        <artifactId>ehcache-core</artifactId>
        <version>${ehcache.version}</version>
    </dependency>
     
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>${spring.version}</version>
    </dependency>
     
    2.配置ApplicationContext.xml (Shiro整合ehcache)
     
     <!-- ehchace缓存管理器:ehcache缓存大对象 -->
    <bean id="ehcacheManager"
    	class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
    	<!-- 注入缓存配置文件的位置 -->
    	<property name="configLocation" value="classpath:ehcache.xml" />
    </bean>
    <!-- shiro缓存管理器:整合ehcache -->
    <bean id="shrioCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
    	<!-- 注入ehcache的缓存管理器 -->
    	<property name="cacheManager" ref="ehcacheManager" />
    </bean>
     
     
    <!-- shiro安全管理器 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    	<!-- 注入 Realm连接安全数据 -->
    	<property name="realm" ref="bosRealm"></property>
    	<!-- 注入shiro的缓存管理器 -->
    	<property name="cacheManager" ref="shiroCacheManager" />
    </bean>
     
     
    <!--通过配置的方式配置realm对象,这里参考 -->
    <!-- <bean id="bosRealm" class="cn.itcast.bos.auth.realm.BosRealm"> 注入缓存具体对象的名字,该名字在ehcache.xml中配置的 
    	<property name="authenticationCacheName" value="BosShiroCache"/> </bean> -->
     
     
    3.BosRealm中添加注解
     
    @Component("bosRealm")
    public class BosRealm extends AuthorizingRealm{
        //注入缓存名称
        @Value("BosShiroCache")//注入缓存具体对象的名字,该名字在ehcache.xml中配置的
        public void setSuperAuthenticationCacheName(String authenticationCacheName){
            super.setAuthenticationCacheName(authenticationCacheName);
        }
    }
     
    4.配置ehcache.xml
     
    <!-- 自定义缓存区域 -->
    <cache name=" BosShiroCache " maxElementsInMemory="10000" eternal="false"
    	timeToIdleSeconds="120" timeToLiveSeconds="120" maxElementsOnDisk="10000000"
    	diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU">
    	<persistence strategy="localTempSwap" />
    </cache>
     
    默认的策略:
    <!-- 硬盘缓存的临时路径 -->
    <diskStore path="java.io.tmpdir" />
    <!-- 默认的缓存区域的缓存策略 maxElementsInMemory:内存中最大容纳的元素数量 eternal:对象是否永生,默认是false
    	timeToIdleSeconds:发呆不用超过多长时间,over死掉 timeToLiveSeconds:活多久就死掉。 maxElementsOnDisk:硬盘上能存放多少元素 
    	diskExpiryThreadIntervalSeconds:轮询的时间,检查的时间。 memoryStoreEvictionPolicy:如果缓存满了怎么办?LRU,LFU,FIFO
    	persistence strategy:如果内存满了,溢出到硬盘 -->
    <defaultCache maxElementsInMemory="10000" eternal="false"
    	timeToIdleSeconds="120" timeToLiveSeconds="120" maxElementsOnDisk="10000000"
    	diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU">
    	<persistence strategy="localTempSwap" />
    </defaultCache>
     
     
    动态菜单优化
    减少无用数据查询(减少SQL的发出)
     
    问题:每次菜单生成的语句太多。生成了很多与功能权限菜单无关的语句,如角色等
    解决:在Function的实体类中,使用@JSON(serialize=fase)
     
    对每个用户菜单进行缓存
     
    问题:每次刷新整个页面都会重新生成菜单,都会重新查询一次数据库。
    解决方案:使用缓存。具体:使用spring 整合ehcache的缓存
     
    1.使用maven坐标引入jar
    略(上面已经引过了)
    2.配置ApplicationContext.xml
     
    xmlns:cache="http://www.springframework.org/schema/cache"
    http://www.springframework.org/schema/cache
    http://www.springframework.org/schema/cache/spring-cache.xsd
     
    <!-- 配置Spring的缓存管理器 -->
    <bean id="springCacheManagerSpring" class="org.springframework.cache.ehcache.EhCacheCacheManager">
    	<!-- 注入ehcache的管理器 - -->
    	<property name="cacheManager" ref="ehCacheManager" />
    </bean>
     
    <!-- 配置缓存的注解驱动,它会自动到spring的bean中寻找缓存相关注解,并使其有效 -->
    <cache:annotation-driven cache-manager="springCacheManagerSpring" />
     
    3.编写ehcache.xml,添加一个新的缓存区域,如MenuSpringCache
     
    4.在方法上添加注解
    提示:spring的缓存管理器默认的key是方法名+参数,如果参数是个对象,那么会发生每次缓存的key都不一样,虽然数据的一样的。因此这种情况下,需要手动指定key
     
    /**
     * 获取用户权限
     */
    @Override
    //value:缓存区域,缓存的东西往哪放
    //缓存的的key的生成策略
    //1.没有参数,key='0'
    //2.有1个参数,那么key是对象本身,一般是对象地址
    //3.有多个参数,那么key是多个对象的hash值
    @Cacheable(value="SpringCache",key="#user.id")
    public List<Function> findFunctionByUser(User user) {
     
    如添加权限,要清除缓存
     
    /**
     * 添加功能
     */
    @Override
    //清除ehcache的某区域的所有对象
    @CacheEvict(value="SpringCache",allEntries=true)
    public void save(Function function) {
     
     
    Hibernate中使用ehcache
     
    1.导入 jar 包:ehcache-1.5.0.jar/ commons-logging.jar/ backport-util-concurrent.jar
    2.开启二级缓存(我要使用二级缓存)
    3.确定二级缓存提供商(我要使用哪个二级缓存)
    4.确定需要缓存内容
    1>配置需要缓存的类
    2>配置需要缓存的集合
    5.配置 ehcache 自定义配置文件
     
    <dependency>
    	<groupId>org.hibernate</groupId>
    	<artifactId>hibernate-ehcache</artifactId>
    	<version>5.0.7.Final</version>
    </dependency>
     
    在 hibernate.cfg.xml 配置缓存,或者交由spring管理,在sessionFactory中配置
     
    开启二级缓存
     
    <!-- 开启二级缓存 -->
    <property name="hibernate.cache.use_second_level_cache">true</property>
     
    确定缓存提供商
     
    <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
     
    确定缓存内容
     
    <!-- 类缓存 -->
    <!-- 指定二级缓存类 ,以及并发访问策略 -->
    <class-cache usage="read-write" class="cn.aric.domain.User"/>
    <!-- 集合缓存 -->
    <collection-cache usage="read-write" collection="cn.aric.doain.Customer.orderSet"/>
     
     
    ehcache 配置文件
     
    文件名:ehcache.xml
    参考官方文件配置
     
    <ehcache>
    	<diskStore path="f:cache" />
    	<defaultCache maxElementsInMemory="10000"
    		eternal="false"
    		timeToIdleSeconds="120"
    		timeToLiveSeconds="120"
    		overflowToDisk="true" />
    	<cache name="hibernateCache"
    		maxElementsInMemory="10000"
    		eternal="false"
    		timeToIdleSeconds="300"
    		timeToLiveSeconds="600"
    		overflowToDisk="true" />
    </ehcache>
     
    测试
     
    //测试二级缓存是否配置成功
    @Test
    public void test(){
        Configuration configuration = new Configuration().configure();
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        //获取session1
        Session session1 = sessionFactory.openSession();
        Transaction tx = session1.beginTransaction();
        User user1 = session1.get(User.class, 10L);
        System.out.println(user1.getUser_code());
        tx.commit();
        session1.close();
     
        //获取session2
        Session session2 = sessionFactory.openSession();
        Transaction tx2 = session2.beginTransaction();
        User user2 = session2.get(User.class, 10L);
        System.out.println(user2.getUser_code());
        tx2.commit();
        session2.close();
    }
     
    查询缓存
     
    查询缓存默认不使用。需要手动开启
    查询缓存:将 HQL 语句与 查询结果进行绑定。通过 HQL 相同语句可以缓存内容。
    默认情况 Query 对象只将查询结果存放在一级和二级缓存,不从一级或二级缓存获取。
    查询缓存就是让 Query 可以从二级缓存获得内容。
     
    <!-- 开启查询缓存 -->
    <property name="hibernate.cache.use_query_cache">true</property>
     
     
    @Test
    public void demo(){
        // 查询缓存
        Session s1 = factory.openSession();
        s1.beginTransaction();
        //1 query查询
        Query q1 = s1.createQuery("from Customer");
        //设置查询缓存为true
        q1.setCacheable(true);
        List<Customer> a1 = q1.list();
        for (Customer c1 : a1) {
            System.out.println(c1);
        }
     
        //2 cid =1 -- 一级缓存获得
        Customer customer = (Customer) s1.get(Customer.class, 1);
        System.out.println(customer);
        s1.getTransaction().commit();
        s1.close();
        System.out.println("----------");
     
        Session s2 = factory.openSession();
        s2.beginTransaction();
        //2 cid =1 -- 二级缓存获得
        Customer customer2 = (Customer) s2.get(Customer.class, 1);
        System.out.println(customer2);
     
        //3 query查询
        Query q2 = s2.createQuery("from Customer");
        q2.setCacheable(true);
        List<Customer> a2 = q2.list();
        for (Customer c2 : a2) {
            System.out.println(c2);
        }
        s2.getTransaction().commit();
        s2.close();
    }
  • 相关阅读:
    【分享】使用 AXI performance monitors (APM)测试MPSoC DDR访问带宽
    测试MPSoC GEM 的1588功能
    使用ffmpeg把mp4转换为NV12文件
    强制开放MPSoC的PS-PL接口
    Java操作数据库指南(之一)
    大数据中台技术架构
    数据仓库到数据中台的演进
    Spark SQL入门到实战之(8)数据倾斜优化
    项目实战从0到1之hive(47)大数据项目之电商数仓(用户行为数据)(十五)
    项目实战从0到1之hive(46)大数据项目之电商数仓(用户行为数据)(十四)
  • 原文地址:https://www.cnblogs.com/timePasser-leoli/p/10451118.html
Copyright © 2011-2022 走看看