精华内容
下载资源
问答
  •  Mybatis提供对缓存的支持,但是在没有配置的默认情况下,它只开启一级缓存,二级缓存需要手动开启。  一级缓存只是相对于同一个SqlSession而言。也就是针对于同一事务,多次执行同一Mapper的相同查询方法,第一...
  • Mybatis 缓存 开启二级缓存

    千次阅读 2021-04-03 14:47:33
    一级缓存Mybatis自己是默认开启的,是不需要我们去管的,不过一级缓存是 SqlSession级别的,在操作数据库的时候我们需要创建SqlSession对象, SqlSession自己有个结构是HashMap的缓存区,每一个SqlSession都有 自己的缓存...

    Mybatis中给我们提供了缓存,其中有一级缓存和二级缓存

    缓存是用来干嘛的?

    1. 当我们使用查询语句到数据库查询,每一次查询都会去访问数据库,频繁的访问数据库就会有压力,缓存就是来缓解数据库压力的,提升系统的性能

    一级缓存

    一级缓存Mybatis自己是默认开启的,是不需要我们去管的,不过一级缓存是
    SqlSession级别的,在操作数据库的时候我们需要创建SqlSession对象,
    SqlSession自己有个结构是HashMap的缓存区,每一个SqlSession都有
    自己的缓存区.
    

    下面作个实验

    代码:

        public void cacheTest()throws Exception{
    //        读取mybatis核心配置文件
            InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
    //        创建SqlSession的创建
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
    //        获取SqlSession
            SqlSession session = factory.openSession();
    //        获取EmpMapper
            EmpMapper mapper = session.getMapper(EmpMapper.class);
    //        根据id查询
            Emp emp1 = mapper.findEmpById(2);
            System.out.println(emp1);
            System.out.println("----------分割线----------");
    //        根据id再次进行相同的查询
            Emp emp2 = mapper.findEmpById(2);
            System.out.println(emp2);
    //        关闭资源
            session.close();
            is.close();
        }
        
        日志信息
    2021-04-03 15:03:04,307 572    [           main] DEBUG m.mapper.EmpMapper.findEmpById  - ==>  Preparing: select * from emp where id=? 
    2021-04-03 15:03:04,339 604    [           main] DEBUG m.mapper.EmpMapper.findEmpById  - ==> Parameters: 2(Integer)
    2021-04-03 15:03:04,360 625    [           main] DEBUG m.mapper.EmpMapper.findEmpById  - <==      Total: 1
    Emp{id=2, name='小赵', age=21, deptId=0}
    ----------分割线----------
    2021-04-03 15:03:04,372 637    [           main] DEBUG       com.ssm.mapper.EmpMapper  - Cache Hit Ratio [com.ssm.mapper.EmpMapper]: 0.0
    Emp{id=2, name='小赵', age=21, deptId=0}
    

    使用同一个SqlSession进行了两次一样的查询,可以从日志信息中看到第一次查询的时候显示发送了sql语句,而第二次查询则没有显示发送sql语句,说明是从缓存中获取的数据,而不是数据库

    什么时候清空一级缓存?

    当我们执行添加,修改,删除操作的时候mybatis会自动清空一级缓存,准确的来说是我们执行commit()事务提交的时候清空

    实验

    代码:

     public void cacheTest2()throws Exception{
    //        读取mybatis核心配置文件
            InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
    //        创建SqlSession的创建
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
    //        获取SqlSession
            SqlSession session = factory.openSession();
    //        获取EmpMapper
            EmpMapper mapper = session.getMapper(EmpMapper.class);
    //        根据id查询
            Emp emp1 = mapper.findEmpById(2);
            System.out.println(emp1);
            System.out.println("----------分割线----------");
    //        删除id为4的员工
            mapper.delEmpById(4);
            session.commit();
            System.out.println("----------分割线----------");
    //        根据id再次进行相同的查询
            Emp emp2 = mapper.findEmpById(2);
            System.out.println(emp2);
    //        关闭资源
            session.close();
            is.close();
        }
        日志信息    
    2021-04-03 15:12:53,322 483    [           main] DEBUG m.mapper.EmpMapper.findEmpById  - ==>  Preparing: select * from emp where id=? 
    2021-04-03 15:12:53,348 509    [           main] DEBUG m.mapper.EmpMapper.findEmpById  - ==> Parameters: 2(Integer)
    2021-04-03 15:12:53,377 538    [           main] DEBUG m.mapper.EmpMapper.findEmpById  - <==      Total: 1
    Emp{id=2, name='小赵', age=21, deptId=0}
    ----------分割线----------
    2021-04-03 15:12:53,385 546    [           main] DEBUG sm.mapper.EmpMapper.delEmpById  - ==>  Preparing: delete from emp where id=? 
    2021-04-03 15:12:53,385 546    [           main] DEBUG sm.mapper.EmpMapper.delEmpById  - ==> Parameters: 4(Integer)
    2021-04-03 15:12:53,415 576    [           main] DEBUG sm.mapper.EmpMapper.delEmpById  - <==    Updates: 1
    2021-04-03 15:12:53,415 576    [           main] DEBUG ansaction.jdbc.JdbcTransaction  - Committing JDBC Connection [com.mysql.jdbc.JDBC4Connection@43015c69]
    ----------分割线----------
    2021-04-03 15:12:53,428 589    [           main] DEBUG       com.ssm.mapper.EmpMapper  - Cache Hit Ratio [com.ssm.mapper.EmpMapper]: 0.0
    2021-04-03 15:12:53,428 589    [           main] DEBUG m.mapper.EmpMapper.findEmpById  - ==>  Preparing: select * from emp where id=? 
    2021-04-03 15:12:53,428 589    [           main] DEBUG m.mapper.EmpMapper.findEmpById  - ==> Parameters: 2(Integer)
    2021-04-03 15:12:53,430 591    [           main] DEBUG m.mapper.EmpMapper.findEmpById  - <==      Total: 1
    Emp{id=2, name='小赵', age=21, deptId=0}
    

    这一次我们在执行第二次查询的之前执行了一次删除的操作,可以看到打印出来的日志信息中出现了3条sql语句,第一条是根据id查询,第二条是根据id删除,第三条又是根据id查询的,这次第二次查询的操作是去数据库中查询的,而不是从缓存中获取的,说明缓存中没有相同的数据

    二级缓存

    二级缓存是Mapper级别的,一个Mapper有着一个缓存区,就是说不管几个
    SqlSession只要他们获取的是同一个Mapper,缓存数据就会是共享的,不过
    二级缓存需要我们自己去开启
    

    开启二级缓存

    1. 第一步:
      先到mybatis的核心配置文件中配置
        <settings>
            <!--开启mybatis二级缓存-->
            <setting name="cacheEnabled" value="true"></setting>
        </settings>
    
    1. 第二步
      开启二级缓存的分开关
    接口开启方法:使用@CacheNamespace注解
    //通过注解开启二级缓存的分开关
    @CacheNamespace
    public interface EmpMapper {
    
    在xml中开启方法:添加"cache"标签
    <mapper namespace="com.ssm.mapper.EmpMapper">
        <!--xml中二级缓存分开关-->
        <cache></cache>
    

    注意:
    xml和接口中只要其中一个开启就可以了,不然会报以下的异常

    Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.lang.IllegalArgumentException: Caches collection already contains value for com.ssm.mapper.EmpMapper
    
    1. 第三步
      让Mapper对应的实例类实现Serializable接口
    //使用mybatis二级缓存的实体类必须实现Serializable接口
    public class Emp implements Serializable{
    

    完成配置以后来做个实验

    代码:

        public void secondLevelCacheTest(){
    //        第一个SqlSession
            SqlSession session = MybatisUtil.getSession();
            EmpMapper mapper = session.getMapper(EmpMapper.class);
            Emp e = mapper.findEmpById(2);
            System.out.println(e);
            session.close();
            System.out.println("----------分割线----------");
    //        第二个SqlSession
            SqlSession session2 = MybatisUtil.getSession();
            EmpMapper mapper2 = session2.getMapper(EmpMapper.class);
            Emp e2 = mapper2.findEmpById(2);
            System.out.println(e2);
            session2.close();
            System.out.println("-----------分割线------------");
    //        第三个SqlSession
            SqlSession session3 = MybatisUtil.getSession();
            EmpMapper mapper3 = session3.getMapper(EmpMapper.class);
            Emp e3 = mapper3.findEmpById(2);
            System.out.println(e3);
            session3.close();
        }
        
         日志信息   
    2021-04-03 15:44:46,137 582    [           main] DEBUG m.mapper.EmpMapper.findEmpById  - ==>  Preparing: select * from emp where id=? 
    2021-04-03 15:44:46,163 608    [           main] DEBUG m.mapper.EmpMapper.findEmpById  - ==> Parameters: 2(Integer)
    2021-04-03 15:44:46,183 628    [           main] DEBUG m.mapper.EmpMapper.findEmpById  - <==      Total: 1
    Emp{id=2, name='小赵', age=21, deptId=0}
    2021-04-03 15:44:46,197 642    [           main] DEBUG ansaction.jdbc.JdbcTransaction  - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@3eb91815]
    2021-04-03 15:44:46,198 643    [           main] DEBUG ansaction.jdbc.JdbcTransaction  - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@3eb91815]
    2021-04-03 15:44:46,198 643    [           main] DEBUG source.pooled.PooledDataSource  - Returned connection 1052317717 to pool.
    ----------分割线----------
    2021-04-03 15:44:46,201 646    [           main] DEBUG       com.ssm.mapper.EmpMapper  - Cache Hit Ratio [com.ssm.mapper.EmpMapper]: 0.5
    Emp{id=2, name='小赵', age=21, deptId=0}
    -----------分割线------------
    2021-04-03 15:44:46,201 646    [           main] DEBUG       com.ssm.mapper.EmpMapper  - Cache Hit Ratio [com.ssm.mapper.EmpMapper]: 0.6666666666666666
    Emp{id=2, name='小赵', age=21, deptId=0}
    

    这次是三次相同的查询,不同的SqlSession,获取的同一个Mapper,只有第一次查询的时候日志显示向数据库发送了sql语句,其他两次都没有发送sql语句,说明其他两次都是从缓存中获取的数据.

    (03/04/2021)

    展开全文
  • SpringBoot 下 mybatis缓存

    千次阅读 2019-03-02 13:14:29
    说起 mybatis,作为 Java 程序员应该是无人不知,它是常用的数据库访问框架。与 Spring 和 Struts 组成了 Java Web 开发的三剑客--- SSM。当然随着 Spring Boot 的发展,现在越来越多的企业采用的是 SpringBoot + ...

    背景:

    说起 mybatis,作为 Java 程序员应该是无人不知,它是常用的数据库访问框架。与 Spring 和 Struts 组成了 Java Web 开发的三剑客--- SSM。当然随着 Spring Boot 的发展,现在越来越多的企业采用的是 SpringBoot + mybatis 的模式开发,我们公司也不例外。而 mybatis 对于我也仅仅停留在会用而已,没想过怎么去了解它,更不知道它的缓存机制了,直到那个生死难忘的 BUG。故事的背景比较长,但并不是啰嗦,只是让读者知道这个 BUG 触发的场景,加深记忆。在遇到类似问题时,可以迅速定位。

    先说下故事的前提,为了防止用户在动态中输入特殊字符,用户的动态都是编码后发到后台,而后台在存入到 DB 表之前会解码以方便在 DB 中查看以及上报到搜索引擎。而在查询用户动态的时候先从 DB 表中读取并在后台做一次编码再传到前端,前端再解码既可以正常展示了。流程如下图:

    有一天后端预发环境发布完毕后,用户的动态页面有的动态显示正常,而有的动态却是被编码过的。看到现象后的第一个反应就是部分被编码了两次,但是编码操作只会在 service 层的 findById 中有。理论不会在上层犯这种低级错误,于是开始排查新增加的代码。发现只要进入了新增加代码中的某个 if 分支则被编码了两次。分支中除了再次调用 findById(必要性不讨论),也无其他特殊代码了。百思不得其解后请教了旁边的老司机,老司机说可能是 mybatis 缓存。于是看了下我代码,将编码的操作从 findById 中移出来后再次发布到预发,正常了,心想老司机不愧是老司机。本次 BUG 触发的有两个条件需要注意:

    •  整个操作过程都在一个函数中,而函数上面加了 @Transactional 的注解(对 mybatis 来说是在同一个 SESSION 中)
    •  一般只会调用 findByIdy 一次,如果进入分支则会调用两次 (第一次调用后做了编码后被缓存,第二次从缓存读后继续被编码)

    于是,便开始谷歌 mybatis 的缓存机制,搜到了一篇非常不错的文章《聊聊 mybatis 的缓存机制》,推荐大家看一下,特别是里面的流程图。同时关注下美团技术官方公众号,上面有很多干货(这不是广告)。但是这篇文章讲到了源码,涉及的比较深。而且并没讲 SpringBoot 下 mybatis 下的一些缓存知识点,遂作此篇,以作补充。

    缓存的配置

    SpringBoot + mybatis 环境搭建很简单而且网上一堆教程,这里不班门弄斧了,记得在项目中将 mytatis 的源码下载下来即可。mybaits 一共有两级缓存:一级缓存的配置 key 是 localCacheScope,而二级缓存的配置 key 是 cacheEnabled,从名字上可以得出以下信息:

    •  一级缓存是本地或者说局部缓存,它不能被关闭,只能配置缓存范围。SESSION 或者 STATEMENT。
    •  二级缓存才是 mybatis 的正统,功能应该会更强大些。

    先来看下在 SpringBoot中 如何配置 mybatis 缓存的相关信息。默认情况下 SpringBoot 下的 mybatis 一级缓存为 SESSION 级别,二级缓存也是打开的,可以在 mybatis 源码中的 org.apache.ibatis.session.Configuration.class 文件中看到(idea中打开),如下图:

    也可以通过以下测试程序查看缓存开启情况

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class LearnApplicationTests {
        private SqlSessionFactory factory;
        @Before
        public void setUp() throws Exception {
    
            InputStream inputStream = Resources.getResourceAsStream("mybatis/mybatis-config.xml");
            factory = new SqlSessionFactoryBuilder().build(inputStream);
        }
        @Test
        public void showDefaultCacheConfiguration() {
            System.out.println("一级缓存范围: " + factory.getConfiguration().getLocalCacheScope());
            System.out.println("二级缓存是否被启用: " + factory.getConfiguration().isCacheEnabled());
        }
    }

    如果要设置一级缓存的缓存级别和开关二级缓存,在 mybatis-config.xml (当然也可以在 application.xml/yml 中配置)加入如下配置即可:

    <settings>
      <setting name="cacheEnabled" value="true/false"/>
      <setting name="localCacheScope" value="SESSION/STATEMENT"/>
    </settings>

    但需要注意的是二级缓存 cacheEnabled 只是个总开关,如果要让二级缓存真正生效还需要在 mapper xml 文件中加入 <cache /> 。一级缓存只在同一 SESSION 或者 STATEMENT 之间共享,二级缓存可以跨 SESSION,开启后它们默认具有如下特性:

    •  映射文件中所有的select语句将被缓存
    •  映射文件中所有的insert、update和delete语句将刷新缓存 

    一二级缓存同时开启的情况下,数据的查询顺序是 二级缓存 -> 一级缓存 -> 数据库。一级缓存比较简单,而二级缓存可以设置更多的属性,只需要在 mapper 的 xml 文件中的 <cache /> 配置即可,具体如下:

    <cache
            type = "org.mybatis.caches.ehcache.LoggingEhcache"  //指定使用的缓存类,mybatis默认使用HashMap进行缓存,可以指定第三方缓存
            eviction = "LRU"  //默认是 LRU 淘汰缓存的算法,有如下几种:
                              //1.LRU – 最近最少使用的:移除最长时间不被使用的对象。 
                              //2.FIFO – 先进先出:按对象进入缓存的顺序来移除它们。  
                              //3.SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。  
                              //4.WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象
            flushInterval = "1000"  //清空缓存的时间间隔,单位毫秒,可以被设置为任意的正整数。  默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。
            size = "100"      //缓存对象的个数,任意正整数,默认值是1024。
           readOnly  = "true"  //缓存是否只读,提高读取效率
           blocking = "true"   //是否使用阻塞缓存,默认为false,当指定为true时将采用BlockingCache进行封装,blocking,
                               //阻塞的意思,使用BlockingCache会在查询缓存时锁住对应的Key,如果缓存命中了则会释放对应的锁,
                               //否则会在查询数据库以后再释放锁这样可以阻止并发情况下多个线程同时查询数据,详情可参考BlockingCache的源码。  
    />

    触发 mybatis 缓存

    (1)配置一级缓存为 SESSION 级别

    Controller 中做两次调用,代码如下:

    @RequestMapping("/getUser")
    public UserEntity getUser(Long id) {
        //第一次调用
        UserEntity user1=userMapper.getOne(id);
        //第二次调用
        UserEntity user2=userMapper.getOne(id);
        return user1;
    }

    调用:http://localhost:8080/getUser?id=1,打印结果如下:

    从图中的 1/2/3/4 可以看出每次 mapper 层的一次接口调用如 getOne 就会创建一个 session,并且在执行完毕后关闭 session。所以两次调用并不在一个 session 中,一级缓存并没有发生作用。开启事务,Controller 层代码如下:

    @RequestMapping("/getUser")
    @Transactional(rollbackFor = Throwable.class)
    public UserEntity getUser(Long id) {
        //第一次调用
        UserEntity user1=userMapper.getOne(id);
        //第二次调用
        UserEntity user2=userMapper.getOne(id);
        return user1;
    }

    打印结果如下:

    由于在同一个事务中,虽然调用了 select 操作两次但是只执行了一次 sql ,缓存发挥了作用。这就跟一开始我遇到的那个 BUG 场景一样:同一 session 且 select 调用 > 1 次。如果在两次调用中间插入 update 操作,缓存会立即失效。只要 session 中有 insert、update 和 delete 语句,该 session 中的缓存会立即被刷新。但是注意这只是在同一 session 之间。不同 session 之间如 session1 和 session2,session1 里的 insert/update/delete 并不会影响 session 2 下的缓存,这在高并发或者分布式的情况下会产生脏数据。所以建议将一级缓存级别调成 statement。

    (2)配置一级缓存为 STATEMENT 级别

    再次将(1)中的无事务和有事务的代码分别执行一遍,打印结果始终如下:

    配置成 SATEMENT 后,一级缓存相当于被关闭了。STATEMENT 级别暂时不好模拟,但是我猜测 STATEMENT 级别即在同一执行 sql 的接口中(如上面的 getOne 中)缓存,出了 getOne 缓存即失效。

    (3)二级缓存,同时为了避免一级缓存的干扰,将一级缓存设置为 STATEMENT

    Controller 中去掉 @Transactional 注解代码如下:

    @RequestMapping("/getUser")
    public UserEntity getUser(Long id) {
        UserEntity user1=userMapper.getOne(id);
        UserEntity user2=userMapper.getOne(id);
        return user1;
    }

    二级缓存开关保证打开,在 mapper xml 文件中加入 <cache />,整个文件代码如下:

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    <mapper namespace="com.binggle.learn.dao.mapper.UserMapper" >
    <resultMap id="BaseResultMap" type="com.binggle.learn.dao.entity.UserEntity" >
        <id column="id" property="id" jdbcType="BIGINT" />
        <result column="name" property="name" jdbcType="VARCHAR" />
        <result column="sex" property="sex"/>
    </resultMap>
    <sql id="Base_Column_List" >
            id, name, sex
    </sql>
    <select id="getOne" parameterType="java.lang.Long" resultMap="BaseResultMap" >
        SELECT
        <include refid="Base_Column_List" />
        FROM users
        WHERE id = #{id};
    </select>
    <cache />
    </mapper>

    执行 http://localhost:8080/getUser?id=1,打印结果如下:

    从图中红框可以看出第二次查询命中缓存,0.5 是命中率,

    再次执行 http://localhost:8080/getUser?id=1 打印结果如下:

    这次一次 sql 也没执行了,所以说二级缓存全局缓存。但它的缓存范围也是有限的,一级缓存在同一个 session 中。二级缓存可以跨 session 但也只能在同一 namespace 中,所谓 namespace 即 mapper xml 文件中。具体实验请看《聊聊 mybatis 的缓存机制》中的关于二级缓存的实验 4 和 5。再看下二级缓存配置对二级缓存的影响,为了明显的看出效果,只改如下配置:

    <cache
            size="1"             //一次只能缓存一个对象
            flushInterval="5000" //刷新时间为 5s
    />

    controller 代码:

    @RequestMapping("/getUser")
    public UserEntity getUser(Long id, Long id2) {
        //第一个对象 1
        System.out.println("================缓存对象 1=================");
        UserEntity user1 = userMapper.getOne(id);
    
        //另一个对象 2
        System.out.println("========缓存对象 2,剔除缓存中的对象 1=======");
        UserEntity user2=userMapper.getOne(id2);
        user2 = userMapper.getOne(id2);
    
        //再次读取第一个对象
        System.out.println("==========缓存被剔除,执行查询 sql===========");
        user1 = userMapper.getOne(id);
    
        //暂停 5s
        try {
            sleep(5000);
        }catch (Exception e){
            e.printStackTrace();
        }
    
        System.out.println("============5s 后再次查询对象 2=============");
        user2 = userMapper.getOne(id2);
    
        return user1;
    }
    

    最后打印的结果如下:

     

    太长了,拼接下:

    可以看出二级缓存只能缓存一个对象且 5s 后就失效了,缓存失效。

    总结:

    我推荐的文章中总结的已经非常好了,直接引用下:

    1、MyBatis一级缓存的生命周期和SqlSession一致。

    2、MyBatis一级缓存内部设计简单,只是一个没有容量限定的HashMap,在缓存的功能性上有所欠缺。

    3、MyBatis的一级缓存最大范围是SqlSession内部,有多个SqlSession或者分布式的环境下,数据库写操作会引起脏数据,建议设定缓存级别为Statement。

    4、MyBatis的二级缓存相对于一级缓存来说,实现了SqlSession之间缓存数据的共享,同时粒度更加的细,能够到namespace级别,通过Cache接口实现类不同的组合,对Cache的可控性也更强。

    5、MyBatis在多表查询时,极大可能会出现脏数据,有设计上的缺陷,安全使用二级缓存的条件比较苛刻。

    6、在分布式环境下,由于默认的MyBatis Cache实现都是基于本地的,分布式环境下必然会出现读取到脏数据,需要使用集中式缓存将MyBatis的Cache接口实现,有一定的开发成本,直接使用Redis、Memcached等分布式缓存可能成本更低,安全性也更高。

    7. 个人建议MyBatis缓存特性在生产环境中进行关闭,单纯作为一个ORM框架使用可能更为合适。

     

    展开全文
  • mybatis缓存配置

    千次阅读 2018-05-25 18:10:45
    mybatis缓存有三种方式:1、一级缓存(基于SqlSession会话级别的;2、二级缓存(基于nameSpace级别的,范围比以及缓存更广);3、第三方缓存mybatis缓存使示意图:一、一级缓存说明:其中一级缓存mybatis默认使用...
    mybatis的缓存有三种方式:
    
    1、一级缓存(基于SqlSession会话级别的;
    2、二级缓存(基于nameSpace级别的,范围比以及缓存更广);

    3、第三方缓存;

    mybatis缓存使示意图:



    一、一级缓存说明:
    其中一级缓存是mybatis默认使用的缓存,无需手动配置,二级缓存需要手动配置;
    一级缓存失效条件
    1)sqlSession不同,由于一级缓存是基于sqlSession级别的,所以当使用不同sqlSession进行查询时缓存也不同;
    2)sqlSession相同,手动清空一级缓存;
    3)sqlSession相同,两次查询之间执行了增删改操作;
    4)sqlSession相同,查询条件不同;

    二、二级缓存相关配置:
    步骤如下:
    1)、开启缓存
    在mybatis配置文件中设置启用缓存
     <settings>
        <setting name="cacheEnabled" value="true"/>
     </settings>
    2)、使用缓存
    在各个XXmapper.xml配置文件中加上
    <cache eviction="FIFO"  flushInterval="10800000"  size="512" readOnly="true" /> 

    属性说明:



    3)、相关的实体类bean对象需要实现序列号接口Serializable

    通过以上配置mybatis二级缓存配置完成!


    三、mybatis缓存相关属性设置:
    在XXmapper.xml配置文件的各个增删改查节点中可以设置以下属性控制缓存;
    useCache:默认为true,当设置false时,则不使用二级缓存(对一级缓存没有影响);
    flushCache:在增删改标签中默认为true,即:进行增删改之后会自动清除一级、二级缓存内容;
    localCacheScpoe:本地缓存作用域,默认为SESSION即开启一级缓存,当设置为STATEMENT时则关闭一级缓存;

    说明:
    在一级缓存和二级缓存同时存在的情况下,查询出来的数据都会自动放到一级缓存中,只有当一级缓存提交或者关闭之后,数据才会转移到二级缓存中,也就是说这个时候才能从二级缓存中取到数据,
    数据查询的时候会先查询二级缓存,再查询一级缓存,最后查询数据库;



    四、第三方缓存配置:
    Mybatis自身的缓存其实是很简陋的,其顶层接口为Cache,查看其具体实现,底层其实就是个Map数据结构而已,因此可以集成第三方缓存接口相关接口,进行数据缓存操作;
    比如集成Ehcache,其实也就是实现了Cache接口,

    具体配置如下:

    1)、基础配置ehcache.xml(省略说明...)

    2)、其它xml配置如下;


    最后:
    如果需要在命名空间中共享相同的缓存配置和实例,在这样的情况下你可以使用 cache-ref 元素来引用另外一个已经配置好的缓存。
    即:在其他XXmapper.xml中配置缓存的引用,
    如下:
    <cache-ref namespace="com.x.x.x.XXXMapper"/>

















    展开全文
  • MyBatis查询缓存

    2021-04-15 11:25:57
    MyBatis提供一级缓存,和二级缓存 一级缓存是SqlSession级别的缓存。在操作数据库时需要构造SqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的SqlSession之间的缓存数据区域(HashMap)是...

    七、查询缓存

    1. 什么是查询缓存

    • MyBatis提供查询缓存,用于减轻数据库压力,提高数据库性能
    • MyBatis提供一级缓存,和二级缓存
    • 一级缓存是SqlSession级别的缓存。在操作数据库时需要构造SqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的SqlSession之间的缓存数据区域(HashMap)是互相不影响的
    • 二级缓存是mapper级别的缓存,多个SqlSession去操作同一个mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的

    在这里插入图片描述

    2. 一级缓存

    2.1 一级缓存工作原理

    在这里插入图片描述

    • 第一次查询id为1的数据,先去找一级缓存中查找是否有id为1的数据,如果没有,从数据库中查询该数据,并将该数据存储到一级缓存中
    • 第二次查询id为1的数据,也先去找一级缓存中查找是否有id为1的数据,缓存中有,直接从缓存中获取该数据,不再查询数据库
    • 如果SqlSession去执行commit操作(执行插入、更新、删除),将清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的数据,避免脏读

    2.2 一级缓存测试

    SqlSession session = MybatisUtil.openSession();
    PersonMapper mapper = session.getMapper(PersonMapper.class);
    System.out.println("第一次查询id为1的数据");
    Person p1 = mapper.findPersonById(1);
    System.out.println(p1);
    
    //执行commit()方法,会清空一级缓存
    session.commit();
    
    System.out.println("第二次查询id为1的数据");
    Person p2 = mapper.findPersonById(1);
    System.out.println(p2);
    session.close();
    

    3. 二级缓存

    3.1 二级缓存工作原理

    在这里插入图片描述

    • SqlSession1去查询id为1的数据,查询到后会将该数据存储到二级缓存中
    • SqlSession2去查询id为1的数据,去缓存中找是否存在数据,如果存在直接从缓存中取出数据
    • 如果SqlSession3去执行相同mapper下sql,执行commit提交,清空该mapper下的二级缓存区域的数据
    • 二级缓存与一级缓存区别,二级缓存的范围更大,多个SqlSession可以共享一个Mapper的二级缓存区域
    • 每个mapper有一个二级缓存区域,按namespace分
    • 如果两个mapper的namespace如果相同,这两个mapper执行sql查询到数据将存在相同的二级缓存区域中

    3.2 开启二级缓存

      在mybatis核心配置文件中配置:cacheEnabled

    设置项描述允许值默认值
    cacheEnabled对在此配置文件下的所有cache 进行全局性开/关设置true \ falsetrue
    <!-- 全局参数设置 -->
    <settings>
        <!-- 开启二级缓存-->
        <setting name="cacheEnabled" value="true"/>
    </settings>
    

      在映射文件中开启二缓存,Mapper.xml下的Sql执行完成会存储到它的缓存区域(HashMap)

    <mapper namespace="com.mybatis.mapper.PersonMapper">
        <!-- 配置当前mapper文件中所有查询语句都放入二级缓存中 -->
        <cache/>
        <select>
            ...
        </select>
    </mapper>
    

    3.3 实体类

      二级缓存中存储数据的实体类必须实现可序列化接口(java.io.Serializable)

    public class Person implements Serializable {
        private Integer id;
        private String name;
        private Integer age;
        private String address;
        //get,set方法省略...
    }
    

    3.4 二级缓存测试

    SqlSession session1 = MybatisUtil.openSession();
    PersonMapper mapper1 = session1.getMapper(PersonMapper.class);
    System.out.println("第一次查询id为1的数据");
    Person p1 = mapper1.findPersonById(1);
    System.out.println(p1);
    session1.close();
    
    SqlSession session2 = MybatisUtil.openSession();
    PersonMapper mapper2 = session2.getMapper(PersonMapper.class);
    System.out.println("第二次查询id为1的数据");
    Person p2 = mapper2.findPersonById(1);
    System.out.println(p2);
    session2.close();
    

    3.5 useCache配置

      在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询。默认情况是true,即该sql使用二级缓存

    <!-- useCache="false"禁用当前sql语句的二级缓存 -->
    <select id="findPerson" resultType="Person" useCache="false">
        select id,name,age,address from person order by id
    </select>
    
    展开全文
  • Mybatis缓存详解

    2020-05-06 21:57:17
    Mybatis缓存详解
  • 文章目录MyBatis缓存机制Spring+MyBatis开启二级缓存1. 创建MyBatis核心配置文件,在settings中开启二级缓存2. 在spring的核心配置文件中,sqlSessionFactory的bean中,将mybatis的配置粘入3. 在mapper.xml映射文件...
  • SpringBoot+Mybatis开启二级缓存

    千次阅读 2019-11-22 22:33:34
    MyBatis 内置了一个强大的事务性查询缓存机制,包括一级...MyBatis 默认是开启一级缓存的,即同一个 sqlSession 每次查询都会先去缓存中查询,没有数据的话,再去数据库获取数据。 <dependency> <gro...
  • 开启mybatis开启二级缓存

    千次阅读 2020-08-19 17:49:56
    Mybatis中有一级缓存和二级缓存,默认情况下一级缓存开启的,而且是不能关闭的。一级缓存是指SqlSession级别的缓存,当在同一个SqlSession中进行相同的SQL语句查询时,第二次以后的查询不会从数据库查询,而是直接...
  • 一级缓存 SqlSession缓存默认开启) SqlSession关闭后(sqlSession.close()),缓存消失。 二级缓存 SqlSessionFactory缓存 当二级缓存开启后,同一个命名空间(namespace) 所有的操作语句,都影响着一个共同的 ...
  • Mybatis(五)—— Mybatis缓存策略 1、主要内容 一级缓存 一级缓存的失效情况 二级缓存介绍 二级缓存使用 缓存的设置 使用第三方缓存 2、具体内容 MyBatis是一个持久化层框架,提供了缓存策略,但是做缓存的话...
  • 原标题:5 分钟,彻底掌握 MyBatis 缓存在计算机的世界中,缓存无处不在,操作系统有操作系统的缓存,数据库也会有数据库的缓存,各种中间件如Redis也是用来充当缓存的作用,编程语言中又可以利用内存来作为缓存。...
  • tkmybatis开启二级缓存

    千次阅读 2018-12-08 09:50:15
    1.MyBatis配置文件开启二级缓存功能  &lt;settings&gt; &lt;settingname="cacheEnabled"value="true"/&gt; &lt;/settings&gt; 2.在 XxxMapper 接口上使用@...
  • 一级缓存是默认开启的,无需其他配置操作,二级缓存则需要手动设置开启。 一级缓存原理: Mybatis的一级缓存是指同一个SqlSession中的操作。一级缓存的作用域是一个SqlSession。 在同一个SqlSession中,执行相同的...
  • 如果已经和spring整合了,mybatis的一级缓存就会失效 因为spring会自动关闭session 所以一级缓存比较鸡肋 通常会使用二级缓存 在mapper上加@CacheNamespace 如果查询和修改一个表中数据的方法不在一个mapper类...
  • mybatis提供查询缓存,用于减轻数据压力,提高数据库性能。 mybaits提供一级缓存,和二级缓存。 一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个(内存区域)数据结构...
  • mybatis自定义缓存实现

    2020-08-10 16:03:19
    mybatis的一级缓存和二级缓存都实现了cache接口,所以要实现自定义缓存而不使用mybatis默认的缓存,那么就要定义一个类让其实现cache接口,并在mapper.xml文件中指明缓存的类型。 过程 实现cache接口的类 ...
  • 1、mybatis缓存机制 2、一级缓存 2、1 工作机制 2、2 失效场景 3、二级缓存 3、1 工作机制 3、2 使用方式 4、与缓存设置有关的设置和属性 5、引入第三方缓存服务
  • Mybatis在生产环境,是否应该开启缓存功能 软件设计活跃区6天前 首先,让我们来测试下Mybatis的一级缓存和二级缓存。 1. Mybatis的一级缓存测试 实验1 开启一级缓存,范围为会话级别,调用三次getStudentById...
  • mybatis缓存

    2017-11-28 10:02:43
    Mybatis分为一级和二级缓存ØMybatis一级缓存为sqlSession级别的缓存 默认开启 相同的sqlsession对象 查询相同条件的结果时存在一级缓存只会查询一次,sqlSession关闭后缓存失效调用cleanCache后缓存被清除,执行过...
  • mybatis开启二级缓存

    万次阅读 热门讨论 2018-06-01 23:15:10
    1.修改配置文件mybatis-config.xml加入&lt;setting name="cacheEnabled"value="true"/&gt;,全局配置参数,需要时再设置cacheEnabled 介绍描述 : ...在mapper.xml中开启缓存,ma...
  • 一级缓存 二级缓存(更高级的缓存缓存顺序: 1.第一次查询先看二级缓存中有没有数据(有的话直接拿出),否则再看一级缓存中有没有数据(有的话直接拿出),否则再去查询数据库 用户》二级缓存》一级缓存》数据库 ...
  • 禁用一级缓存 二级缓存使用分布式存储。如 redis等
  • MyBatis中,不同SqlSession作用域中开启了两个相同的查询操作。但是在控制台的输出中一直显示没有命中缓存,持续进行SQL查询操作。 代码如下: public class DaoTest { private static final Logger LOGGER = ...
  • springboot mybatis 开启二级缓存 步骤: 1.我们要在mapper的xml文件下配置cache节点 2. 注意这个配置之后该mapper下的所有的查询语句都会走缓存 如果我们想指定莫一条查询语句不走缓存,我们就可以再该sql下 配置 ...
  • mybatis缓存机制

    万次阅读 多人点赞 2018-09-16 08:18:32
    一、mybatis和同是持久层的hibernate一样,都存在着缓存机制,今天来说... (1)一级缓存:一级缓存mybatsi已近为我们自动开启,不用我们手动操作,而且我们是关闭不了的!!但是我们可以手动清除缓存。(SqlSess...
  • Mybatis缓存机制详解

    千次阅读 2018-10-17 00:04:21
    Mybatis缓存机制详解 ...mybatis默认情况下只会开启一级缓存,也就是局部的 session 会话缓存。 首先我们要知道什么是查询缓存?查询缓存又有什么作用? 功能:mybatis提供查询缓存,用于减轻数据...
  • spring整合mybatis开启mybatis的二级缓存

    千次阅读 2017-03-17 16:49:30
    第一步,配置mybatis的配置文件sqlMapConfig.xml <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> 第二...
  • mybatis 全局缓存解析

    千次阅读 2018-07-12 10:44:56
    mybatis 全局缓存解析 基本概念 疑问 例子 缓存解析 第一节 默认缓存 第二节 缓存的四种类型 第三节 缓存的结构 自定义缓存 自定义缓存的例子 总结 参考 mybatis 全局缓存解析 价值 ★★☆ ...
  • Mybatis缓存(实例)

    2020-04-18 15:53:01
    用实例来演示Mybatis缓存的使用。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 45,129
精华内容 18,051
关键字:

mybatis开启缓存