Mybatis 缓存 开启二级缓存

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)

    原文作者:落炘
    原文地址: https://blog.csdn.net/weixin_45906369/article/details/115416120
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞