MyBatis学习-5

MyBatis学习-5

本次学习我将为大家讲解一下MyBatis的缓存,它可以在我们实际开发使用时为我们节省很大的时间,类似JDBC的缓存池。

一级缓存

一级缓存,(本地缓存),sqlSession级别的缓存,一级缓存是一直开起的,与数据库同一次会话期间查询到的数据会放在本地缓存中。以后我们如果需要相同的数据,直接从缓存中拿,没必要去查询数据库;
下面我们通过使用一个sqlSession来获取两次相同的数据看看他们到底是不是同一个内容

   @Test
    public void test09() throws IOException{
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();

        SqlSession openSession = sqlSessionFactory.openSession();
//        SqlSession openSession2 = sqlSessionFactory.openSession();

        try {
            EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
            Employee emp1 = mapper.getEmpById(1);
//            EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);
            System.out.println(emp1);
            //xxx
            Employee emp2 = mapper.getEmpById(1);
            System.out.println(emp2);
            System.out.println(emp1 == emp2);
        }finally {
            openSession.close();
        }
    }

我们发现输出的结果是true说明两次getMappper返回的是同一个数据,再到我们的控制台去看,它说DEBUG [main] - ==> Preparing: select id,last_name Lastname,email,gender from tbl_employee where id = ? DEBUG [main] - ==> Parameters: 1(Integer) DEBUG [main] - <== Total: 1 Employee{id=1, Lastname='lvyonghao', email='snake_lvyonghao@163.com', gender='1', department=null} Employee{id=1, Lastname='lvyonghao', email='snake_lvyonghao@163.com', gender='1', department=null}证明了我们确实只做了一次查询。
下面我们讨论一级缓存失效的情况

  • sqlSession不同
    如果我再新建一个sqlSession同样的查询语句他会不会再次从缓存池中拿出来呢?
    @Test
    public void test09() throws IOException{
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();

        SqlSession openSession = sqlSessionFactory.openSession();
        SqlSession openSession2 = sqlSessionFactory.openSession();

        try {
            EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
            Employee emp1 = mapper.getEmpById(1);
            EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);
            System.out.println(emp1);
            //xxx
            Employee emp2 = mapper2.getEmpById(1);
            System.out.println(emp2);
            System.out.println(emp1 == emp2);
        }finally {
            openSession.close();
        }
    }

运行的结果是false,并且我们在控制台中也可以看到它确实发送了两次sql,说明这个时候sqlSession缓存失效了。

  • sqlSession相同,查询条件不同
    @Test
    public void test09() throws IOException{
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();

        SqlSession openSession = sqlSessionFactory.openSession();
//        SqlSession openSession2 = sqlSessionFactory.openSession();

        try {
            EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
            Employee emp1 = mapper.getEmpById(1);
//            EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);
            System.out.println(emp1);
            //xxx
            Employee emp2 = mapper.getEmpById(3);
            System.out.println(emp2);
            System.out.println(emp1 == emp2);
        }finally {
            openSession.close();
        }

结果是必然的,false,查询条件不同必然没有启用一级缓存。

  • sqlSession相同,两次查询期间执行了增删改语句
    @Test
    public void test09() throws IOException{
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();

        SqlSession openSession = sqlSessionFactory.openSession();
        SqlSession openSession2 = sqlSessionFactory.openSession();

        try {
            EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
            Employee emp1 = mapper.getEmpById(1);
            EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);
            System.out.println(emp1);
            //xxx

            mapper.addEmp(new Employee(null,"huwenhao","hunwenhao@outlook.com","1"));
            System.out.println("数据添加成功");

            Employee emp2 = mapper.getEmpById(1);
            System.out.println(emp2);
            System.out.println(emp1 == emp2);
        }finally {
            openSession.close();
        }
    }

结果是false,因为我们的增删改操作可能会对当前数据有影响。

  • sqlSession相同,手动清除了一级缓存
    @Test
    public void test09() throws IOException{
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();

        SqlSession openSession = sqlSessionFactory.openSession();
        SqlSession openSession2 = sqlSessionFactory.openSession();

        try {
            EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
            Employee emp1 = mapper.getEmpById(1);
            EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);
            System.out.println(emp1);
            //xxx


            openSession.clearCache();

//            mapper.addEmp(new Employee(null,"huwenhao","hunwenhao@outlook.com","1"));
//            System.out.println("数据添加成功");

            Employee emp2 = mapper2.getEmpById(1);
            System.out.println(emp2);
            System.out.println(emp1 == emp2);
        }finally {
            openSession.close();
        }
    }

当我们把一级缓存清理后,结果是false,这个我就不用多说什么了。
实际上sqlSession级别的缓存其实就是一个Map


二级缓存

二级缓存也称为全局缓存,它是基于namespace级别的缓存,对应的就是我们XML的namespace,一个namespace对应一个二级缓存。

  1. 一个会话,查询一条数据,这个数据就会被放在当前会话的一级缓存。
  2. 如果会话关闭,一级缓存中的数据会被保存到二级缓存中,新的会话查询信息就可以参照二级缓存中的内容
  3. 不同的namespace查出的数据会放在在自己对应的缓存中(Map)

下面我们就实践一下吧

  1. 首先二级缓存是自动开启的,我们不需要手动开启二级缓存配置,当然你也可以显示的配置设个属性,来到我们MyBatis的配置文件当中的setting标签当中,设置cacheEnabled为true。
  2. 我们去Mapper.xml当中配置二级缓存,我们只需要在文件当中添加<cache></cachae>标签就可以了,当然他也有几个属性我们也来介绍一下:
  • evication:缓存回收策略

LRU : 最近少使用的,移除长时间不使用的对象(默认)
FIFD : 先进先出,按对象进入缓存的顺序移除他们
SOFT :软引用,移除基于垃圾回收器状态和软引用规则的对象。
WEAK : 弱引用,更积极的移除给予垃圾收集器状态和弱引用规则的对象。

  • flushInterval:刷新间隔时间(设置为毫秒数)
  • readOnly:是否只读设置为true和false
  • size :设置缓存中放置多少个元素
  • type=“”:自定义缓存的全类名,实现Cache接口即可
  1. 我们的POJO需要实现序列化接口Serializable
    @Test
    public void test10() throws IOException{
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();

        SqlSession openSession = sqlSessionFactory.openSession();
        SqlSession openSession2 = sqlSessionFactory.openSession();

        try {
            EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
            EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);

            Employee emp01 = mapper.getEmpById(1);
            System.out.println(emp01);
            openSession.close();

            Employee emp02 = mapper2.getEmpById(1);
            System.out.println(emp02);


        }finally {
            openSession.close();
        }
    }

我们在日志中可以看到这么一句话Cache Hit Ratio [com.snake_lvyonghao.MyBatis.Dao.EmployeeMapper]: 0.5意思就是在缓存中命中,也就意味着我们从二级缓存中找到了。


SSM框架源码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值