0
点赞
收藏
分享

微信扫一扫

MyBatis-缓存


MyBatis缓存

缓存的目的就是为了提高执行效率

**内存:**不能永久存储数据,我们都知道内存他是​​断电即丢失​​​的,我们要想把数据永久存储,可以写入到磁盘上,但是缺点就是慢,而且我们的数据也不都是必须要永久存储的所以这里我们就需要用到缓存上
**缓存:**可以读取效率高,而且只是临时存储,每次不必从磁盘或者数据库中拿。

MyBatis为我们提供了一个​​缓存​​​的机制,用于储存​​临时的​​​,​​热点​​的数据,经常使用的数据。这个缓存是存储是存储到内存中的。

MyBatis-缓存_redis


缓存的重要性不言而喻的,使用缓存,我们可以避免频繁的与数据库操作,尤其是在查询较多,缓存命中的几率好越高的情况下,我们使用缓存效率就很明显。

MyBatis缓存机制

MyBatis是默认开的一级缓存,也就是Session范围级别的缓存

一级缓存

  1. 默认开启的,线程级别的缓存,​​SqlSession的缓存​
  2. 在一个SqlSession生命周期中有效,即当SqlSession.close()后,缓存就被清空。
  3. 在同一个SqlSession中,MyBatis会把执行的方法通过算法生成一个缓存的键值,将键值和结果封装到一个Map里,如果后续的键值一致,则会从map中获取值,不必再操作数据库。
  4. 不同的SqlSession之间的缓存是相互隔离的
  5. 用一个SqlSession,可以通过配置使得在查询前清空缓存—​​flushCache=“true”​
  6. 任何的UPDATE,INSERT,DELETE语句都会清空缓存

eg:例如MyBatis一级缓存实例

@Test
public void testQueryByNameDeptNo2() throws Exception {
SqlSession session = SessionUtils.getSession();
System.out.println("=============一级缓存(第一个sqlsession1)=============");
System.out.println("=============第一次查询sqlsession1=============");
List<Emp01> list = session.getMapper(EmpMapper.class).selectEmpByNameDeptNo2("MARTIN", 30);
for (Emp01 emp01 : list) {
System.out.println(emp01);
}

System.out.println("=============第二次查询=============");
List<Emp01> list2 = session.getMapper(EmpMapper.class).selectEmpByNameDeptNo2("MARTIN", 30);
for (Emp01 emp01 : list2) {
System.out.println(emp01);
}
session.commit();
session.close();
}

缓存采用的临时存储的概念,见下:

MyBatis-缓存_缓存_02


可以看到执行了两句相同的查询操作后,只执行了一条SQL语句,那么原因就是MyBatis默认将第一个SQL查询的结果与参数封装到一个Map里,第二次查会先匹配查询查询参数,与第一次查询的参数相同,ok—>直接去Map里去获取

一级缓存是SqlSession级别的,见下:

我们开启两条SqlSession–>

@Test
public void testQueryByNameDeptNo2() throws Exception {
SqlSession session = SessionUtils.getSession();
System.out.println("=============一级缓存(第一个sqlsession1)=============");
System.out.println("=============第一次查询sqlsession1=============");
List<Emp01> list = session.getMapper(EmpMapper.class).selectEmpByNameDeptNo2("MARTIN", 30);
for (Emp01 emp01 : list) {
System.out.println(emp01);
}

System.out.println("=============第二次查询=============");
List<Emp01> list2 = session.getMapper(EmpMapper.class).selectEmpByNameDeptNo2("MARTIN", 30);
for (Emp01 emp01 : list2) {
System.out.println(emp01);
}

System.out.println();
SqlSession session2 = SessionUtils.getSession();
System.out.println("=============一级缓存(第二个sqlsession2)=============");
System.out.println("=============第一次查询sqlsession2=============");
List<Emp01> list3 = session2.getMapper(EmpMapper.class).selectEmpByNameDeptNo2("MARTIN", 30);
for (Emp01 emp01 : list3) {
System.out.println(emp01);
}

System.out.println("=============第二次查询sqlsession2=============");
List<Emp01> list4 = session2.getMapper(EmpMapper.class).selectEmpByNameDeptNo2("MARTIN", 30);
for (Emp01 emp01 : list4) {
System.out.println(emp01);
}
session.commit();
session.close();

session2.commit();
session2.close();
}

MyBatis-缓存_sql_03


我们看到这是就开启了两条的SQL语句,原因就证明了一级缓存是SqlSession级别的。

更新操作会清空缓存,见下

@Test
public void testQueryByNameDeptNo2() throws Exception { //MARTIN
SqlSession session = SessionUtils.getSession();
System.out.println("=============一级缓存(第一个sqlsession1)=============");
System.out.println("=============第一次查询sqlsession1=============");
List<Emp01> list = session.getMapper(EmpMapper.class).selectEmpByNameDeptNo2("MARTIN", 30);
for (Emp01 emp01 : list) {
System.out.println(emp01);
}

System.out.println("=============修改操作=============");
Emp01 emp0 = new Emp01();
emp0.seteName("TYGGIRE");
emp0.setEmpNo(7654);
emp0.setSalary(4500F);
session.getMapper(EmpMapper.class).updateEmp(emp0);

System.out.println("=============第二次查询=============");
List<Emp01> list2 = session.getMapper(EmpMapper.class).selectEmpByNameDeptNo2("MARTIN", 30);
for (Emp01 emp01 : list2) {
System.out.println(emp01);
}
session.commit();
session.close();
}

MyBatis-缓存_sql_04


我们可以看到,之要执行了DML操作后,就会清空缓存,下次再查询相同条件的时候就不会再查询到原来的数据了,这也是符合正常的业务逻辑的,保证了数据的一致性。

二级缓存

  1. 进程级别的缓存,​​SqlSessionFactory的缓存​
  2. 在一个SqlSessionFactory的生命周期内有效,可以在多个SqlSession生命周期中共享
    3.​​​ 默认关闭​​​,需要使用的时候,需要为某个命名空间开启二级缓存在mapper.xml文件里中配置一个​​cache标签​​。

<!--开启二级缓存 需要对实体类进行是实体化-->
<cache />

  1. 由于在更新是会刷新缓存,因此需要注意使用场景,查询频率很高,更新频率很低时使用,即经常使用select,相对较少使用delete,insert,update语句的时候
  2. 二级缓存是以namespace为单位的,不同的namepace,尽量是在单表操作的时候使用二级缓存。

二级缓存的应用场景

  1. 对于访问多的查询请求并且用户但对查询的结构实时性要求较不高的情况下,可以使用MyBatis的二级缓存,降低数据的访问量,提高访问效率,如电话账单查询。
  2. 根据需求设置相应的FlushInterval:刷新间隔时间,比如二十分钟等等。

eg:二级缓存实例
开启二级缓存

1.首先在mybatis-config.xml里配置全局的缓存开关

<settings>
<setting name = "cacheEnabled" value = "true" />
</settings>

  1. 在对应的XXXmapper.xml里使用标签​​<cache/>​​开启二级缓存
  2. 将pojomapper映射类实现Serializable接口🔥

@Test
public void testQueryByNameDeptNo2() throws Exception { //MARTIN
SqlSession session = SessionUtils.getSession();
System.out.println("=============一级缓存(第一个sqlsession1)=============");
System.out.println("=============第一次查询sqlsession1=============");
List<Emp01> list = session.getMapper(EmpMapper.class).selectEmpByNameDeptNo2("TYGGIRE", 30);
for (Emp01 emp01 : list) {
System.out.println(emp01);
}

System.out.println("=============修改操作=============");
Emp01 emp0 = new Emp01();
emp0.seteName("TYGGIRE");
emp0.setEmpNo(7654);
emp0.setSalary(4500F);
// session.getMapper(EmpMapper.class).updateEmp(emp0);

System.out.println("=============第二次查询=============");
List<Emp01> list2 = session.getMapper(EmpMapper.class).selectEmpByNameDeptNo2("TYGGIRE", 30);
for (Emp01 emp01 : list2) {
System.out.println(emp01);
}
session.commit();
session.close();
}

查询结果:

MyBatis-缓存_二级缓存_05


这里如果要演示二级缓存的使用,需要闯将两个不同的Sqlsession,去完成同一个条件的查询操作,见下:

@Test
public void testQueryByNameDeptNo2() throws Exception { //
SqlSession session = SessionUtils.getSession();
System.out.println("=============一级缓存(第一个sqlsession1)=============");
System.out.println("=============第一次查询sqlsession1=============");
List<Emp01> list = session.getMapper(EmpMapper.class).selectEmpByNameDeptNo2("MARTIN", 30);
for (Emp01 emp01 : list) {
System.out.println(emp01);
}


System.out.println("=============第二次查询=============");
List<Emp01> list2 = session.getMapper(EmpMapper.class).selectEmpByNameDeptNo2("MARTIN", 30);
for (Emp01 emp01 : list2) {
System.out.println(emp01);
}
session.close(); // 关闭SqlSession,将数据存储到二级缓存

SqlSession session2 = SessionUtils.getSession();
System.out.println("=============一级缓存(第二个sqlsession2)=============");
System.out.println("=============第一次查询sqlsession2=============");
List<Emp01> list3 = session2.getMapper(EmpMapper.class).selectEmpByNameDeptNo2("MARTIN", 30);
for (Emp01 emp01 : list3) {
System.out.println(emp01);
}

System.out.println("=============第二次查询sqlsession2=============");
List<Emp01> list4 = session2.getMapper(EmpMapper.class).selectEmpByNameDeptNo2("MARTIN", 30);
for (Emp01 emp01 : list4) {
System.out.println(emp01);
}
session2.close();
}

MyBatis-缓存_二级缓存_06


举报

相关推荐

0 条评论