mybatis高级知之查询缓存

1.查询缓存

1.1什么是查询缓存

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


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

二级缓存是mapper级别的缓存
    多个SQLSession去操做同一个Mapper的sql语句,多个SqlSession能够共用二级缓存,二级缓存是SQLSession的

为何要存储?
    若是缓存中有数据就不用在从数据库中获取,大大提升系统的性能。
1234567891011121314复制代码

2一级缓存

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

        若是在SQLSession去执行commit操做(执行插入,更新,删除)清空SQLSession中的一级缓存。这样作的目的
        为了缓存中永远存储的是最新的信息,避免脏读       
        第二次发起查询用户id为1的用户信息,先去查询缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取
        用户信息
    2.2一级缓存测试
        mybatis默认支持一级缓存,不须要在配置文件去配置
        按照上边一级缓存原理步骤测试
12345678910111213复制代码
测试代码
            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();

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

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开启二级缓存
12345678910复制代码
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/>1234567891011复制代码
3.2调用pojo类实现序列化接口
12复制代码
public class User implements Serializables{
        private int id;
        private String username;
        private String sex;
        private Date birthday;
        private String address;
    }1234567复制代码
为了将缓存的数据取出执行序列化操做,由于二级缓存的存储介质多种多样,不必定在内存

3.3测试方法
1234复制代码
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();


            }
123456789101112131415161718192021222324252627282930313233复制代码
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接口的实现类
1234567891011121314151617181920212223242526272829303132复制代码
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;
            }
        }

123456789101112131415161718192021复制代码
4.3配置信息
12复制代码
配置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"/>1234567复制代码
3.4加入ehcache包
    ehcache-core-2.6.5.jar
    mybatis-ehcache-1.0.2jar

    3.5加入ehcache的配置文件
123456复制代码
在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> 123456789101112131415复制代码
属性说明:
             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二级缓存应用场景
        应用场景:
123456789101112131415161718复制代码

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

5.局限性:
  mybatis二级缓存对细粒度的数据级别的缓存实现很差,好比以下需求:对商品信息进行缓存,因为商品信息查询访问量大,
可是要求用户每次都能查询最新的商品信息,此时若是使用mybatis的二级缓存就没法实现当一个商品变化时只刷新该商品的缓
存信息而不刷新其它商品的信息,由于mybaits的二级缓存区域以mapper为单位划分,当一个商品信息变化会将全部商品信息
的缓存数据所有清空。解决此类问题须要在业务层根据需求对数据有针对性缓存。复制代码
相关文章
相关标签/搜索