mybatis高级知识(四)&查询缓存

1.查询缓存

1.1什么是查询缓存

mybatis提供查询缓存,用于减轻数据压力,提高数据库性能
mybatis提供一级缓存二级缓存


一级缓存是SQLSession级别的缓存
    在操作数据库时需要构造SQLSession对象,在对象中有一个数据结构(HashMap)用户存储缓存数据
不同的SQLSession之间的缓存数据的区域(HashMap)是互不影响的。

二级缓存是mapper级别的缓存
    多个SQLSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是SQLSession的

为什么要存储?
    如果缓存中有数据就不用在从数据库中获取,大大提高系统的性能。

2一级缓存

    2.1一级缓存的工作原理
        第一次发起查询用户id为1的用户的信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户
        信息
        得到用户信息,将用户信息存储到一级存储中

        如果在SQLSession去执行commit操作(执行插入,更新,删除)清空SQLSession中的一级缓存。这样做的目的
        为了缓存中永远存储的是最新的信息,避免脏读       
        第二次发起查询用户id为1的用户信息,先去查询缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取
        用户信息
    2.2一级缓存测试
        mybatis默认支持一级缓存,不需要在配置文件去配置
        按照上边一级缓存原理步骤测试
测试代码
            public testCacher1() throws Exception{
            SqlSession sqlSesssion=sqlSessionFactory.openSession();//创建代理对象
            UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
                //下边查询使用一个SqlSession
                //第一次发起请求,查询id为1的用户
                User uyser=userMapper.findUserById(1);
                System.out.println(:user1);
                //如果SQLSession去执行commit操作(执行插入,更新,删除) 清空SQLSession中的一级缓存
                这样做的目的是为了让缓存中存储的是最新的信息,避main脏读
                //更新user的信息
                user.setUsername(“测试用户22”);
                userMapper.updateUser(user1);
                //执行commint操作去清除缓存
                SQLSession.commit();
                //第二次发起请求,查询id为1的用户
                User user2=username.fiondUserById(1);
                System.out.println(user2);
                sqlSession.close();

            }
    2.3一级缓存的应用
    正式开发,是将mybatis和spring进行整合开发,事务空载子service中
    一个service方法中包括很多mapper方法调用
    service
        //开始执行执行时,开启事务,创建SQLSession对象
        //第一调用mapper的方法findUserByID(1);
        //第二次调用mapper的方法findUserByID(1);从一级缓存中取数据
        //方法结束sqlSession关闭
    如果是俩次service调用查询相同的用户信息,不走一级缓存,因为service方法结束,SQLSession就关闭
    一级缓存就清空。    

3.二级缓存

    首先开启mybatis的二级缓存
    SQLSession去查询用户id为1的用户信息,查询到用户信息会将查询数据存储到二级缓存中
    如果SQLSession去执行相同mapper下sql,执行commit提交,清空该mapper下的二级缓存区域的数据
    SQLSession去查询用户id为1的用户信息,去缓存中查中是否存在数据,如果存在直接从缓存中取出数据
    二级缓存与一级缓存区别:二级缓存的范围更大,多个SQLSession可以共享一个UserMapper二级缓存
    UserMapper有一个二级缓存区域(按照namespace分),其他的mapper也有自己的缓存区域(按照namespace分)
    每一个namespace的mapper有一个二级缓存区域,如果俩个mapper的namespace如果相同,这俩个
    mapper执行sql查询到的数据就存在相同的二级缓存区域中
3.1开启二级缓存
mybatis的二级缓存是mapper范围级别,除了在SqlMapConfig.xml设置二级缓存的总开关,还要在具体的mapper.xml
        中开启二级缓存
        二级缓存使用,需要在主文件中进行配置:
            ①启用二级缓存
            <!-- 启用二级缓存 -->
            <setting name="cacheEnabled" value="true"/>

    在UserMapper中开启二级缓存,UserMapper.xml下的sql执行完成会存储到它的缓存区域(HashMap)、
    <mapper namespace="mybaties.mapper.User,apper">
    <!--开启本mapper的namespace下的二级缓存-->
    <cache/>
3.2调用pojo类实现序列化接口
public class User implements Serializables{
        private int id;
        private String username;
        private String sex;
        private Date birthday;
        private String address;
    }
为了将缓存的数据取出执行序列化操作,因为二级缓存的存储介质多种多样,不一定在内存

3.3测试方法
public testCacher2() throws Exception{
            SqlSession sqlSesssion=sqlSessionFactory.openSession();
            SqlSession sqlSesssion2=sqlSessionFactory.openSession();
            SqlSession sqlSesssion3=sqlSessionFactory.openSession();

            //创建代理对象
            UserMapper userMapper=sqlSession.getMapper(UserMapper.class);

                //下边查询使用一个SqlSession
                //第一次发起请求,查询id为1的用户
                User uyser=userMapper.findUserById(1);
                System.out.println(:user1);
                //这里执行关闭操作,将SQLSession中的数据写到二级缓存区域
                SQLSession.close();             

                //使用SQLSession执行commit()操作
                UserMapper userMapper3=sqlSession3.getMapper(UserMapper.class);
                User user=userMapper3.findUserById(1);
                user.setUsername(“测试用户22”);
                userMapper3.updateUser(user1);
                //执行commint操作去清除缓存
                SQLSession3.commit();
                SQLSession3.close();

                UserMapper userMapper2=sqlSession2.getMapper(UserMapper.class);
                //第二次发起请求,查询id为1的用户
                User user2=userMapper2.findUserById(1);
                Stystem.out.println(user2);
                sqlSession2.close();


            }
    3.4useCache配置
    ①.设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认情况是true,即该sql使用二级缓存。
    <select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">
    总结:针对每次查询都需要最新的数据sql,要设置成useCache=false,禁用二级缓存。
    ②.清空缓存
    <insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" flushCache="true"> 
    总结:一般下执行完commit操作都需要刷新缓存,flushCache=true表示刷新缓存,这样可以避免数据库脏读。
    注意:

    (1)当为select语句时:

    flushCache默认为false,表示任何时候语句被调用,都不会去清空本地缓存和二级缓存。

    useCache默认为true,表示会将本条语句的结果进行二级缓存。

    (2)当为insert、update、delete语句时:

    flushCache默认为true,表示任何时候语句被调用,都会导致本地缓存和二级缓存被清空。

    useCache属性在该情况下没有。

    当为select语句的时候,如果没有去配置flushCache、useCache,那么默认是启用缓存的,所以,如果有必要,那么就需要人工修改配置

    4.mybatis整合ehcache
        4.1分布式缓存
        我们系统为了提高系统并发,性能。一般对系统进行分布式部署。(集群部署方式)
        不使用分布缓冲池缓存的数据在各自服务器单独存储,不方便系统开发,所以要对分布式缓存对缓存数据进行集中管理
        mybatis无法实现分布式缓存。需要和其他分布式缓存框架进行整合
        4.2整合的方法
        mybatis提供了一个cache接口,如果要实现自己的存储逻辑,实现cache接口开发即可
        mybatis和ehcache整合,mybatis和ehcache集合包中提供了一个cache接口的实现类
public interface Cache{
                String getId();
                void putObject(Object key ,Object value);
                Object getObject(Object key);


            }
        mybatis默认实现的cache类是
        public class PerpetualCache implements Cache{
            private String id;
            private Map<Object,Object> cache=new HashMap<Object,Object>();
            public PerpetualCache(String id){
                this.id=id;

            }
            public String getId(){
                return id;
            }
        }

4.3配置信息
配置mapper中的cache中的type为ehcache对cache接口的实现
    <mapper namespace="mybatis.mapper.UserMapper">
        <!-- 开启mapper的namespace下的二级缓存
            type:指定Cache接口的实现类的类型,mybatis默认使用PerpetualCache
            要和ehcache整合:需要配置type为ehcache实现cache接口类型
            -->
        <caahe type="org.mybatis.caches.ehcache.EhcacheCache"/>
    3.4加入ehcache包
    ehcache-core-2.6.5.jar
    mybatis-ehcache-1.0.2jar

    3.5加入ehcache的配置文件
在classpath下配置
             1 <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             2 xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
             3 <diskStore path="F:\develop\ehcache" />
             4 <defaultCache
             5 maxElementsInMemory="1000"
             6 maxElementsOnDisk="10000000"
             7 eternal="false"
             8 overflowToDisk="false"
             9 timeToIdleSeconds="120"
            10 timeToLiveSeconds="120"
            11 diskExpiryThreadIntervalSeconds="120"
            12 memoryStoreEvictionPolicy="LRU">
            13 </defaultCache>
            14 </ehcache> 
        属性说明:
             diskStore:指定数据在磁盘中的存储位置。
             defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache便会采用<defalutCache/>指定的的管理策略
            以下属性是必须的:
             maxElementsInMemory - 在内存中缓存的element的最大数目 
             maxElementsOnDisk - 在磁盘上缓存的element的最大数目,若是0表示无穷大
             eternal - 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断
             overflowToDisk - 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上
            以下属性是可选的:
             timeToIdleSeconds - 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大
             timeToLiveSeconds - 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大
            diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区.
             diskPersistent - 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。
             diskExpiryThreadIntervalSeconds - 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作
             memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出
    4二级缓存应用场景
        应用场景:

   对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用mybatis二级缓存技术降低数据库访问量,提高访
问速度,业务场景比如:耗时较高的统计分析sql、电话账单查询sql等。实现方法如下:通过设置刷新间隔时间,由mybatis每隔一段时
间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushInterval,比如设置为30分钟、60分钟、24小时等,根据需求而定。

    5.局限性:
  mybatis二级缓存对细粒度的数据级别的缓存实现不好,比如如下需求:对商品信息进行缓存,由于商品信息查询访问量大,
但是要求用户每次都能查询最新的商品信息,此时如果使用mybatis的二级缓存就无法实现当一个商品变化时只刷新该商品的缓
存信息而不刷新其它商品的信息,因为mybaits的二级缓存区域以mapper为单位划分,当一个商品信息变化会将所有商品信息
的缓存数据全部清空。解决此类问题需要在业务层根据需求对数据有针对性缓存。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值