最全面的Mybatis教程,从“开局”到“通关”(二)(下)

简介: 最全面的Mybatis教程,从“开局”到“通关”(二)(下)

十二、Mybatis缓存


1️⃣Mybatis缓存简介


为什么要使用缓存? 每次查询都要连接数据库,比较耗资源,我们把查询到的数据暂存到内存里面,下次查询的时候,从内存读取, 这个地方就叫缓存。

什么样的数据适用于缓存? 经常查询且不经常改变的数据


Mybatis系统默认定义了两级缓存:


默认情况下,只有一级缓存开启(SqlSession缓存,也称为本地缓存)

二级缓存需要手动配置,它是基于namespace级别的缓存

Mybatis定义了缓存接口Cache,可以通过实现Cache接口来自定义二级缓存


2️⃣ 一级缓存


🍀一级缓存是sqlsession级别的缓存


  • 在操作数据库时,需要构造sqlsession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据
  • 不同的sqlsession之间的缓存区域是互相不影响的。


🍀一级缓存工作原理

一级缓存工作原理图解:

5be95b6995854fab8779a7dee1d7c6bc.png


第一次发起查询sql查询用户id为1的用户,先去找缓存中是否有id为1的用户,如果没有,再去数据库查询用户信息。得到用户信息,将用户信息存储到一级缓存中

如果sqlsession执行了commit操作(插入,更新,删除),会清空sqlsession中的一级缓存,避免脏读


第二次发起查询id为1的用户,缓存中如果找到了,直接从缓存中获取用户信息

MyBatis默认支持并开启一级缓存


🍀一级缓存测试步骤


(1)开启日志

(2)测试在一个Session中查询两次

(3)查看日志输出


🍀一级缓存演示


Mapper接口:

User getUserById(int id);

xxxMapper.xml:


<select id="getUserById" parameterType="int" resultType="User">
      select * from mybatis.user where id=#{id}
  </select>


Test.java:

 @Test
  public void getUserById(){
      SqlSession sqlSession = MybatisUtils.getSqlSession();
      UserMapper mapper = sqlSession.getMapper(UserMapper.class);
      User u=mapper.getUserById(1);
      System.out.println(u);
      System.out.println("=============");
      User user=mapper.getUserById(1);
      System.out.println(user);
      System.out.println(u==user);
      sqlSession.close();
  }

010831f95950472e902e160e6c031e84.png


🍀缓存失效的情况


当sqlSession不同

当sqlSession对象相同的时候,查询的条件不同,原因是第一次查询时候,一级缓存中没有第二次查询所需要的数据

当sqlSession对象相同,两次查询之间进行了插入的操作

当sqlSession对象相同,手动清除了一级缓存中的数据


🍀一级缓存生命周期


MyBatis在开启一个数据库会话时,会创建一个新的SqlSession对象,SqlSession对象中会有一个新的Executor对象,Executor对象中持有一个新的PerpetualCache对象;当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。

如果SqlSession调用了close()方法,会释放掉一级缓存PerpetualCache对象,一级缓存将不可用。

如果SqlSession调用了clearCache(),会清空PerpetualCache对象中的数据,但是该对象仍可使用。

SqlSession中执行了任何一个update操作(update()、delete()、insert()),都会清空PerpetualCache对象的数据,但是该对象可以继续使用。


3️⃣二级缓存


🍀二级缓存是mapper级别的缓存


多个sqlsession去操作同一个mapper的sql语句,多个sqlsession可以共用二级缓存,所得到的数据会存在二级缓存区域

二级缓存是跨sqlsession的

二级缓存相比一级缓存的范围更大(按namespace来划分),多个sqlsession可以共享一个二级缓存


🍀二级缓存实现原理


020a9895d2e744cd91258e6e601c2a3a.png


首先要手动开启MyBatis二级缓存

在config.xml设置二级缓存开关

<settings>
    <!--开启二级缓存-->
    <setting name="cacheEnabled" value="true"/>       
</settings>
<!-- 需要将映射的javabean类实现序列化 -->

还要在具体的mapper.xml开启二级缓存

<!--开启本Mapper的namespace下的二级缓存-->
<cache eviction="LRU" flushInterval="100000"/>

🍀禁用二级缓存


在statement中可以设置useCache=false,禁用当前select语句的二级缓存,默认情况为true

<select id="getStudentById" parameterType="java.lang.Integer" resultType="Student" useCache="false">

在实际开发中,针对每次查询都需要最新的数据sql,要设置为useCache=“false” ,禁用二级缓存。


🍀flushCache标签:刷新缓存(清空缓存)

<select id="getStudentById" parameterType="java.lang.Integer" resultType="Student" flushCache="true">

一般下执行完commit操作都需要刷新缓存,flushCache="true 表示刷新缓存,可以避免脏读。


🍀二级缓存应用场景


对于访问多的查询请求并且用户对查询结果实时性要求不高的情况下,可采用MyBatis二级缓存,降低数据库访问量,提高访问速度,如电话账单查询。

根据需求设置相应的flushInterval:刷新间隔时间,比如三十分钟,24小时等。


🍀二级缓存局限性


MyBatis二级缓存对细粒度的数据级别的缓存实现不好,比如如下需求:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品信息,此时如果使用MyBatis的二级缓存就无法实现当一个商品变化时只刷新该商品的缓存信息而不刷新其它商品的信息,因为MyBatis的二级缓存区域以mapper为单位划分,当一个商品信息变化会将所有商品信息的缓存数据全部清空。解决此类问题需要在业务层根据需求对数据有针对性缓存。


🍀使用二级缓存


(1)开启全局缓存


<!-- 虽然默认开启,但是写上可以让看代码的人明白 -->
<setting name="cacheEnabled" value="true"/>


(2)在要使用二级缓存的Mapper.xml中,写标签


<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>


(3)测试

@Test
public void getUserById2(){
 SqlSession sqlSession = MybatisUtils.getSqlSession();
 SqlSession sqlSession2 = MybatisUtils.getSqlSession();
 UserMapper mapper = sqlSession.getMapper(UserMapper.class);
 UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
 User u=mapper.getUserById(1);
 System.out.println(u);
 sqlSession.close();
 System.out.println("============");
 User user = mapper2.getUserById(1);
 System.out.println(user==u);
 sqlSession2.close();
}

7626844154f840748cc4c528b1a22f8d.png

(2)问题


我们需要实体类序列化,否则会抛出异常


(4)总结


二级缓存在同一个Mapper下有效

所有的数据都会先放在一级缓存中

当会话提交或者关闭,数据会被转存到二级缓存中


4️⃣ 缓存原理


ab9a12f06adf4e63a2b76b0a0d5e4c67.png


5️⃣自定义缓存EhCache


🍀EhCache简介


EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认CacheProvider。Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。


🍀EhCache使用


(1)导包

<!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->
<dependency>
 <groupId>org.mybatis.caches</groupId>
 <artifactId>mybatis-ehcache</artifactId>
 <version>1.2.2</version>
</dependency>

(2)写入配置文件(resources->ehcache.xml)

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<!-- 磁盘缓存位置 -->
<diskStore path="java.io.tmpdir/ehcache"/>
<!-- 默认缓存 -->
<defaultCache
       maxEntriesLocalHeap="10000"
       eternal="false"
       timeToIdleSeconds="120"
       timeToLiveSeconds="120"
       maxEntriesLocalDisk="10000000"
       diskExpiryThreadIntervalSeconds="120"
       memoryStoreEvictionPolicy="LRU">
 <persistence strategy="localTempSwap"/>
</defaultCache>
<!-- helloworld缓存 -->
<cache name="HelloWorldCache"
      maxElementsInMemory="1000"
      eternal="false"
      timeToIdleSeconds="5"
      timeToLiveSeconds="5"
      overflowToDisk="false"
      memoryStoreEvictionPolicy="LRU"/>
</ehcache>

(3)在Mapper中指定


<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>


(4)测试

@Test
public void getUserById2(){
 SqlSession sqlSession = MybatisUtils.getSqlSession();
 SqlSession sqlSession2 = MybatisUtils.getSqlSession();
 UserMapper mapper = sqlSession.getMapper(UserMapper.class);
 UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
 User u=mapper.getUserById(1);
 System.out.println(u);
 sqlSession.close();
 System.out.println("============");
 User user = mapper2.getUserById(1);
 System.out.println(user==u);
 sqlSession2.close();
}

🍀自定义缓存


只要实现了org.apache.ibatis.cache.Cache接口,就能定义自己的缓存,但是实现比较复杂,只需要会使用就行,ehcache是继承了AbstractEhcacheCache,该类已经实现了Cache接口。

  public class MyCache implements Cache {
      @Override
      public String getId() {
          return null;
      }
      @Override
      public void putObject(Object key, Object value) {
      }
      @Override
      public Object getObject(Object key) {
          return null;
      }
      @Override
      public Object removeObject(Object key) {
          return null;
      }
      @Override
      public void clear() {
      }
      @Override
      public int getSize() {
          return 0;
      }
  }


🍀实际开发中使用的缓存

在实际开发中,我们更多的使用Redis来做缓存。

相关文章
|
12天前
|
SQL Java 数据库连接
【MyBatisPlus·最新教程】包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段
MyBatis-Plus是一个MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。本文讲解了最新版MP的使用教程,包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段等核心功能。
【MyBatisPlus·最新教程】包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段
|
21天前
|
SQL 缓存 Java
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
本文详细介绍了MyBatis的各种常见用法MyBatis多级缓存、逆向工程、分页插件 包括获取参数值和结果的各种情况、自定义映射resultMap、动态SQL
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
|
29天前
|
SQL 存储 数据库
深入理解@TableField注解的使用-MybatisPlus教程
`@TableField`注解在MyBatis-Plus中是一个非常灵活和强大的工具,能够帮助开发者精细控制实体类与数据库表字段之间的映射关系。通过合理使用 `@TableField`注解,可以实现字段名称映射、自动填充、条件查询以及自定义类型处理等高级功能。这些功能在实际开发中,可以显著提高代码的可读性和维护性。如果需要进一步优化和管理你的MyBatis-Plus应用程
117 3
|
2月前
|
前端开发 Java Apache
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
本文详细讲解了如何整合Apache Shiro与Spring Boot项目,包括数据库准备、项目配置、实体类、Mapper、Service、Controller的创建和配置,以及Shiro的配置和使用。
354 1
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
|
4月前
|
XML 缓存 Java
一文讲明Mybatis 的使用 超详细 【爆肝两万字教程】
文章提供了一份详尽的Mybatis使用教程,涵盖了Mybatis的简介、环境搭建、基本操作、配置解析、日志使用、分页、注解开发、多对一和一对多关系处理、动态SQL以及缓存机制等方面的内容,并提供了相应的代码示例和测试用例。
一文讲明Mybatis 的使用 超详细 【爆肝两万字教程】
|
4月前
|
SQL Java 数据库连接
Spring Boot联手MyBatis,打造开发利器:从入门到精通,实战教程带你飞越编程高峰!
【8月更文挑战第29天】Spring Boot与MyBatis分别是Java快速开发和持久层框架的优秀代表。本文通过整合Spring Boot与MyBatis,展示了如何在项目中添加相关依赖、配置数据源及MyBatis,并通过实战示例介绍了实体类、Mapper接口及Controller的创建过程。通过本文,你将学会如何利用这两款工具提高开发效率,实现数据的增删查改等复杂操作,为实际项目开发提供有力支持。
202 0
|
4月前
|
Java 关系型数据库 MySQL
MyBatisPlus如何根据id批量查询?Required request parameter ‘id‘ for method 解决方法是看青戈大佬MybatisPlus的教程
MyBatisPlus如何根据id批量查询?Required request parameter ‘id‘ for method 解决方法是看青戈大佬MybatisPlus的教程
|
7月前
|
XML Java 数据库连接
Mybatis-Plus学习小项目及详细教程
Mybatis-Plus学习小项目及详细教程
|
7月前
|
XML 监控 druid
【Java专题_02】springboot+mybatis+pagehelper分页插件+druid数据源详细教程
【Java专题_02】springboot+mybatis+pagehelper分页插件+druid数据源详细教程
108 0
下一篇
无影云桌面