MyBatis框架:第十章:mybatis缓存

简介: MyBatis框架:第十章:mybatis缓存

mybatis缓存

说明: 缓存指的是把一些常用的数据,保存到一个可以高速读取的缓冲区中。方便程序在频繁读取的时候,可以快速的取出数据。这就叫做缓存。

一级缓存指的是,这些缓存的数据,在同一个SqlSession中多次SQL操作都可以获取。

二级缓存指的是,这些缓存的数据。在同一个Mapper中有一个cache缓存对象。多个SqlSession对象可以共享这些数据。

15.1、mybatis的一级缓存

MyBatis的一级缓存默认开启。同一个SqlSession中查询,可以从一级缓存中取数据。

15.1.1、一级缓存的演示

创建实体Bean对象

public class User {
  private int id;
  private String lastName;
  private int sex;

创建UserMapper接口

public interface UserMapper {
  public User queryUserById(int id);
}

创建UserMappper配置文件

<!-- 
  queryUserById 根据id查询用户
 -->
<select id="queryUserById" parameterType="int" resultType="com.bean.User">
  select id,last_name lastName,sex  from t_user where id = #{id}
</select>

测试一级缓存的测试代码:

@Test
public void testQueryUserById() {
  SqlSession session = sqlSessionFactory.openSession();
  try {
    UserMapper userMapper =  session.getMapper(UserMapper.class);
    User user = userMapper.queryUserById(1);
    System.out.println(user);
    User user1 = userMapper.queryUserById(1);
    System.out.println(user1);
  } finally {
    session.close();
  }
}

测试的结果:

在上面的测试代码中,我们不难看出。我们查询了两次。可是只发出一条sql语句。

这是由于第二次查询的时候,是直接从一级缓存中取出的数据。而没有查询数据库。

15.1.2、一级缓存的管理

缓存失效的四种情况:

1.不在同一个SqlSession对象中

2.执行语句的参数不同。缓存中也不存在数据。

3.执行增,删,改,语句,会清空掉缓存

4.手动清空缓存数据

15.1.2.1、不在同一个缓存对象中(SqlSession或SqlSessionFactory)

测试的代码:

@Test
public void testCacheFail1() {
  SqlSession session = sqlSessionFactory.openSession();
  try {
    UserMapper userMapper =  session.getMapper(UserMapper.class);
    User user = userMapper.queryUserById(1);
    System.out.println(user);
  } finally {
    session.close();
  }
  SqlSession session2 = sqlSessionFactory.openSession();
  try {
    UserMapper userMapper =  session2.getMapper(UserMapper.class);
    User user = userMapper.queryUserById(1);
    System.out.println(user);
  } finally {
    session2.close();
  }
}

测试的结果:

15.1.2.2、执行语句的参数不同。缓存中也不存在数据。

测试的代码:

@Test
public void testCacheFail2() {
  SqlSession session = sqlSessionFactory.openSession();
  try {
    UserMapper userMapper = session.getMapper(UserMapper.class);      
    System.out.println( userMapper.queryUserById(1) );
    System.out.println( userMapper.queryUserById(2) );
  } finally {
    session.close();
  }
}

测试的结果:

15.1.2.3、执行增,删,改,语句,会清空掉缓存

增加的更新方法

public int updateUser(User user);

增加的方法对应的xml配置

<update id="updateUser" parameterType="com.bean.User">
  update t_user set last_name = #{lastName} , sex = #{sex} where id = #{id}
</update>

测试的代码:

@Test
public void testCacheFail3() {
  SqlSession session = sqlSessionFactory.openSession();
  try {
    UserMapper userMapper = session.getMapper(UserMapper.class);
    System.out.println( userMapper.queryUserById(1) );
    userMapper.updateUser(new User(2, "2xxxxx", 1));
    System.out.println( userMapper.queryUserById(1) );
    session.commit();
  } finally {
    session.close();
  }
}

测试的结果:

15.1.2.4、手动清空缓存数据

测试的代码:

@Test
public void testCacheFail4() {
  SqlSession session = sqlSessionFactory.openSession();
  try {
    UserMapper userMapper = session.getMapper(UserMapper.class);
    System.out.println( userMapper.queryUserById(1) );
    session.clearCache();
    System.out.println( userMapper.queryUserById(1) );
    session.commit();
  } finally {
    session.close();
  }
}

测试的结果:

15.2、mybatis的二级缓存

二级缓存的图解示意

二级缓存的使用:

myBatis的二级缓存默认是不开启的。我们需要在mybatis的核心配置文件中配置setting选项 和 在Mapper的配置文件中加入cache标签。并且需要被二级缓存的对象必须要实现java的序列化接口。

一:配置全局的setting

<!-- 启用二级缓存  -->
<setting name="cacheEnabled" value="true"/>

二:在需要使用二级缓存的Mapper配置文件中加入cache标签

<!-- cache标签配置二级缓存 -->
<cache></cache>

三:需要二级缓存的数据对象必须要实现序列化接口java.io.Serializable

15.2.1、二级缓存的演示

示例代码:

@Test
public void testQueryUserById() {
  SqlSession session = sqlSessionFactory.openSession();
  UserMapper userMapper = session.getMapper(UserMapper.class);
  User user = userMapper.queryUserById(1);
  System.out.println(user);
  session.close();    
  SqlSession session1 = sqlSessionFactory.openSession();
  UserMapper userMapper1 = session1.getMapper(UserMapper.class);
  user = userMapper1.queryUserById(1);
  System.out.println(user);
  session1.close();
}

查询结果:

15.2.2、useCache="false"的演示和说明

在Mapper配置文件的定义select查询语句的标签中,可以给某个select查询语句定义不使用二级缓存。

这个时候,咱们再执行上次的二级缓存查询测试代码,得到的结果如下:

15.2.3、flushCache="true"的演示和说明

默认情况下,在所有的insert。update。delete标签中,都有flushCache=”true”。这样的属性。

表示当要执行增,删,改语句的时候,都需要清空缓存中的数据。清空之后,再次的查询就不会从二级缓存中获取数据。

这样做的好处是为了避免出现脏读的情况。

增,删,改清空缓存的测试代码。

@Test
public void testQueryUserById2() {
  SqlSession session = sqlSessionFactory.openSession();
  UserMapper userMapper = session.getMapper(UserMapper.class);
  User user = userMapper.queryUserById(1);
  System.out.println(user);
  session.close();
  SqlSession session2 = sqlSessionFactory.openSession();
  UserMapper userMapper2 = session2.getMapper(UserMapper.class);
  userMapper2.updateUser(new User(1, "更新了", 1));
  session2.commit();
  session2.close();
  SqlSession session1 = sqlSessionFactory.openSession();
  UserMapper userMapper1 = session1.getMapper(UserMapper.class);
  user = userMapper1.queryUserById(1);
  System.out.println(user);
  session1.close();
}

查询的结果:

当我们把update标签上的属性改为 flushCache=“false” 的时候。就会出现脏读的情况。

update t_user set last_name = #{lastName} , sex = #{sex} where id = #{id}

再次执行上面清空缓存的测试代码。就会出现脏读的情况。

15.2.4、标签的介绍和说明

默认的标签的作用:

1、映射语句文件中的所有 select 语句将会被缓存。

2、射语句文件中的所有 insert,update 和 delete 语句会刷新缓存。

3、缓存会使用 Least Recently Used(LRU,最近最少使用的)算法来收回。

4、根据时间表(比如 no Flush Interval,没有刷新间隔), 缓存不会以任何时间顺序 来刷新。

5、缓存会存储列表集合或对象(无论查询方法返回什么)的 1024 个引用。

6、缓存会被视为是 read/write(可读/可写)的缓存,意味着对象检索不是共享的,而 且可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。

cache标签示例解析:

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

eviction 属性表示缓存策略。

LRU – 最近最少使用的:移除最长时间不被使用的对象(这是默认策略)。
FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。

flushInterval 属性表示间隔多长时间刷新一下缓冲区,清理一下溢出的数据。以毫秒为单位。

size 属性表示缓存中可以保存多少个对象。默认是1024。

readOnly 属性表示是否只读。如果设置为true。表示缓存中只有一个对象。如果设置为false(默认为false)每次取出来都会反序列化拷贝一份。

type 属性表示自定义二级缓存对象。

15.2.6、EhCache缓存的使用

EhCache缓存介绍:

EhCache 是一个专业的纯Java的进程缓存框架。具有快速、精干等特点,是Hibernate中默认的CacheProvider缓存提供者。

由于MyBatis中定义了Cache缓存接口极大的方便了我们对缓存的自定义切换和扩展。

整合EhCache到MyBatis的步骤:

1.导入ehcache的包。以及整合包。

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
 <!-- 磁盘保存路径 -->
 <diskStore path="D:\ehcache" />
 <defaultCache 
   maxElementsInMemory="1000" 
   maxElementsOnDisk="10000000"
   eternal="false" 
   overflowToDisk="true" 
   timeToIdleSeconds="120"
   timeToLiveSeconds="120" 
   diskExpiryThreadIntervalSeconds="120"
   memoryStoreEvictionPolicy="LRU">
 </defaultCache>
</ehcache>
<!-- 
属性说明:
l diskStore:指定数据在磁盘中的存储位置。
以下属性是必须的:
l maxElementsInMemory - 在内存中缓存的element的最大数目 
l maxElementsOnDisk - 在磁盘上缓存的element的最大数目,若是0表示无穷大
l eternal - 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断
l overflowToDisk - 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上
以下属性是可选的:
l timeToIdleSeconds - 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大
l timeToLiveSeconds - 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大
 diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区.
l diskPersistent - 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。
l diskExpiryThreadIntervalSeconds - 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作
    l memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出)
 -->

3.配置cache标签的type属性

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

16、缓存的使用顺序说明:

1、当我们执行一个查询语句的时候。mybatis会先去二级缓存中查询数据。如果二级缓存中没有。就到一级缓存中查找。

2、如果二级缓存和一级缓存都没有。就发sql语句到数据库中去查询。

3、查询出来之后马上把数据保存到一级缓存中。

4、当SqlSession关闭的时候,会把一级缓存中的数据保存到二级缓存中。

相关文章
|
2月前
|
缓存 NoSQL Java
什么是缓存?如何在 Spring Boot 中使用缓存框架
什么是缓存?如何在 Spring Boot 中使用缓存框架
61 0
|
4月前
|
缓存 Java 数据库连接
mybatis复习05,mybatis的缓存机制(一级缓存和二级缓存及第三方缓存)
文章介绍了MyBatis的缓存机制,包括一级缓存和二级缓存的配置和使用,以及如何整合第三方缓存EHCache。详细解释了一级缓存的生命周期、二级缓存的开启条件和配置属性,以及如何通过ehcache.xml配置文件和logback.xml日志配置文件来实现EHCache的整合。
mybatis复习05,mybatis的缓存机制(一级缓存和二级缓存及第三方缓存)
|
8天前
|
存储 缓存 自然语言处理
SCOPE:面向大语言模型长序列生成的双阶段KV缓存优化框架
KV缓存是大语言模型(LLM)处理长文本的关键性能瓶颈,现有研究多聚焦于预填充阶段优化,忽视了解码阶段的重要性。本文提出SCOPE框架,通过分离预填充与解码阶段的KV缓存策略,实现高效管理。SCOPE保留预填充阶段的关键信息,并在解码阶段引入滑动窗口等策略,确保重要特征的有效选取。实验表明,SCOPE仅用35%原始内存即可达到接近完整缓存的性能水平,显著提升了长文本生成任务的效率和准确性。
21 3
SCOPE:面向大语言模型长序列生成的双阶段KV缓存优化框架
|
1月前
|
缓存 Java 数据库连接
MyBatis缓存机制
MyBatis提供两级缓存机制:一级缓存(Local Cache)默认开启,作用范围为SqlSession,重复查询时直接从缓存读取;二级缓存(Second Level Cache)需手动开启,作用于Mapper级别,支持跨SqlSession共享数据,减少数据库访问,提升性能。
32 1
|
1月前
|
缓存 Java 数据库连接
深入探讨:Spring与MyBatis中的连接池与缓存机制
Spring 与 MyBatis 提供了强大的连接池和缓存机制,通过合理配置和使用这些机制,可以显著提升应用的性能和可扩展性。连接池通过复用数据库连接减少了连接创建和销毁的开销,而 MyBatis 的一级缓存和二级缓存则通过缓存查询结果减少了数据库访问次数。在实际应用中,结合具体的业务需求和系统架构,优化连接池和缓存的配置,是提升系统性能的重要手段。
63 4
|
2月前
|
SQL Java 数据库连接
持久层框架MyBatisPlus
持久层框架MyBatisPlus
54 1
持久层框架MyBatisPlus
|
2月前
|
SQL 缓存 Java
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
本文详细介绍了MyBatis的各种常见用法MyBatis多级缓存、逆向工程、分页插件 包括获取参数值和结果的各种情况、自定义映射resultMap、动态SQL
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
|
2月前
|
SQL 缓存 Java
MyBatis如何关闭一级缓存(分注解和xml两种方式)
MyBatis如何关闭一级缓存(分注解和xml两种方式)
86 5
|
4月前
|
缓存 Java 开发工具
Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
三级缓存是Spring框架里,一个经典的技术点,它很好地解决了循环依赖的问题,也是很多面试中会被问到的问题,本文从源码入手,详细剖析Spring三级缓存的来龙去脉。
234 24
|
3月前
|
缓存 Java 数据库连接
使用MyBatis缓存的简单案例
MyBatis 是一种流行的持久层框架,支持自定义 SQL 执行、映射及复杂查询。本文介绍了如何在 Spring Boot 项目中集成 MyBatis 并实现一级和二级缓存,以提高查询性能,减少数据库访问。通过具体的电商系统案例,详细讲解了项目搭建、缓存配置、实体类创建、Mapper 编写、Service 层实现及缓存测试等步骤。