【MyBatis 深入学习】MyBatis缓存级别

8 篇文章 0 订阅
2 篇文章 0 订阅

MyBatis缓存级别

1. 概述

缓存,顾名思义其实就是就是为了提高查询效率。MyBatis的缓存同样是如此。那么接下来让我们看下MyBatis缓存到底是怎么回事。
点击 此连接 查看Demo 源码

2. 环境准备

mapper

public interface PlanTaskMapper {
  List<PlanTask> findAll(String projectId);
}

pojo

@AllArgsConstructor
@NoArgsConstructor
@Data
@ToString
public class PlanTask implements Serializable {
  private String projectId;
  private String planContent;
  private String id;
}

mybatis xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
    <properties resource="jdbc.properties"/>

    <typeAliases>
        <!--包扫描起别名  类的短路径名首字母小写-->
        <package name="plus.chendd.pojo"/>
    </typeAliases>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc_driver}"/>
                <property name="url" value="${jdbc_url}"/>
                <property name="username" value="${jdbc_username}"/>
                <property name="password" value="${jdbc_password}"/>
            </dataSource>
        </environment>
    </environments>

    <!--加载mapper映射文件-->
    <mappers>
        <!--通过包扫描加载所有的mapper-->
        <package name="plus.chendd.mapper"/>
    </mappers>
</configuration>

初步测试案例

public class Test001 {
  
  private SqlSession sqlSession;
  
  @Before
  public void init() {
    SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    InputStream resourceAsStream;
    try {
      resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
    SqlSessionFactory build = sqlSessionFactoryBuilder.build(resourceAsStream);
    sqlSession = build.openSession();
  }
  
  
  public void print(List<PlanTask> list) {
    for (Object o : list) {
      System.out.println(o);
    }
  }
  
  @Test
  public void test01() {
    PlanTaskMapper mapper = sqlSession.getMapper(PlanTaskMapper.class);
    List<PlanTask> all = mapper.findAll("11111");
    print(all);
  }
  
  @After
  public void after() {
    sqlSession.close();
  }
}

3. 一级缓存

3.1 实例

  public void test01() {
    PlanTaskMapper mapper = sqlSession.getMapper(PlanTaskMapper.class);
    List<PlanTask> all = mapper.findAll("11111");
    print(all);
  
    List<PlanTask> all1 = mapper.findAll("11111");
    print(all1);
  }

在这里插入图片描述

通过上述示例可以看到,mybatis具有缓存的。因为在第二次进行查询的时候,并没有连接数据库而是直接返回值

3.2 一级缓存的原理

在这里插入图片描述

一级缓存是基于sqlSession进行缓存的,默认开启,是一种内存型缓存,不要求实体类对象实现Serializable接口
缓存生成的规则是:namespace + SQL.id + args + offset. 通过一个hash函数来生成一个值。将查询的结果作为key。最后以key/value 的形式存储到内存中

3.3 反向验证

  @Test
  public void test02() {
    PlanTaskMapper mapper = sqlSession.getMapper(PlanTaskMapper.class);
    List<PlanTask> all = mapper.findAll("11111");
    print(all);
  
    PlanTaskMapper mapper1 = sqlSession01.getMapper(PlanTaskMapper.class);
    List<PlanTask> all1 = mapper1.findAll("11111");
    print(all1);
  }

在这里插入图片描述
通过上图可以看到,如果使用两个不同的sqlSession来执行mapper的话,其结果是不具备缓存的。

3.4 清除缓存

当发生编辑操作,进行commit的时候,会清除sqlSession 缓存。

当我们添加如下代码:

sqlSession.commit();

重新执行后,会出现如下截图:(出现了两次sql 查询
在这里插入图片描述

4. 二级缓存

  1. 二级缓存是以namespace为标记的缓存,可以是由一个SqlSessionFactory创建的SqlSession之间共享缓存数据。默认并不开启。下面的代码中创建了两个SqlSession,执行相同的SQL语句,尝试让第二个SqlSession使用第一个SqlSession查询后缓存的数据。
  2. 要求实体类必须实现序列化接口

在这里插入图片描述

其实就是获取两个sqlSession 来进行数据查询,在某种情况下两个sqlSession可以实现数据共享

public void testFindDeptByDetpno()   {
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
Emp emp = mapper.findByEmpno(7521);
System.out.println(emp);
// SqlSession提交之后,才会将查询的结果放入二级缓存
sqlSession.commit();


EmpMapper mapper2 = sqlSession2.getMapper(EmpMapper.class);
Emp emp2 = mapper2.findByEmpno(7521);
System.out.println(emp2);
}

注意其中的commit(),执行该命令后才会将该SqlSession的查询结果从一级缓存中放入二级缓存,供其他SqlSession使用。另外执行SqlSession的close()也会将该SqlSession的查询结果从一级缓存中放入二级缓存。两种方式区别在当前SqlSession是否关闭了

4.1 二级缓存开启方式

  • 第一步:

全局开关:在sqlMapConfig.xml文件中的标签配置开启二级缓存

<settings>
    <setting name="cacheEnabled" value="true"/>
</settings>
  • 第二步:

分开关:在要开启二级缓存的mapper文件中开启缓存

<mapper namespace="com.msb.mapper.EmployeeMapper">
    <cache/>
</mapper>
  • 第三步:

二级缓存未必完全使用内存,有可能占用硬盘存储,缓存中存储的JavaBean对象必须实现序列化接口

public class Emp implements  Serializable {  }
  • 第四步:

如果在加入Cache元素的前提下让个别select 元素不使用缓存,可以使用useCache属性,设置为false。useCache控制当前sql语句是否启用缓存 flushCache控制当前sql执行一次后是否刷新缓存

<select id="findByEmpno" resultType="emp" useCache="true">

经过设置后,查询结果如图所示。发现第一个SqlSession会首先去二级缓存中查找,如果不存在,就查询数据库,在commit()或者close()的时候将数据放入到二级缓存。第二个SqlSession执行相同SQL语句查询时就直接从二级缓存中获取了

5. 总结

以上就是对MyBatis中 一级二级缓存的认识,尤其是一级缓存,有效的利用缓存可以减少跟数据库IO 的操作,提高效率。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值