mybatis学习教程中级(九)mybatis一级缓存、二级缓存(重点)

简介: 1、前言 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。

1、前言

将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。

看看我们常说说的缓存


这个就是我们常说的缓存,那么我们今天要看的肯定是mybatis缓存。

mybatis的缓存如下:

2、mybatis的一级缓存:


是sqlsession级别的缓存。就是你查询之后只要不commit(一般增删改才需要),就是不关闭sqlsession会话,就拥有缓存,mybatis默认支持一级缓存。

注意:如果与spring整合,我们还清楚的记得spring最后都要关闭sqlsession的,所以呀就不支持一级缓存了(虽然然并卵,但是还是值得我们学习一下)。

第一次发出一个查询sqlsql查询结果写入sqlsession的一级缓存中,缓存使用的数据结构是一个map<key,value>

keyhashcode+sql+sql输入参数+输出参数(sql的唯一标识)

value:用户信息

同一个sqlsession再次发出相同的sql,就从缓存中取不走数据库。如果两次中间出现commit操作(修改、添加、删除),本sqlsession中的一级缓存区域全部清空,下次再去缓存中查询不到所以要从数据库查询,从数据库查询到再写入缓存。



key里面部分数据:100881661:3415680886:com.ycy.mybatis.dao.UserMapper.getUserById:0:2147483647:SELECT  * FROM USER WHERE id=?:1:development

我们一直进入源码里面,进入execute里面去看看,因为我用的idea,进入源码看起来都吐了,没有Eclipse方便。没事可以看看,第二次他就读取这个key,那么久可以直接从原来的本地缓存读取。然后就这么完美的实现一级缓存。

实例:

package com.ycy.mybatis.test;

import com.ycy.mybatis.dao.OrdersCustomMapper;
import com.ycy.mybatis.dao.UserMapper;
import com.ycy.mybatis.dao.impl.UserMappermpl;
import com.ycy.mybatis.module.Orders;
import com.ycy.mybatis.module.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * Created by Administrator on 2015/8/31 0031.
 */
public class MybatisTest9 {
    private SqlSessionFactory sqlSessionFactory = null;
    @Before
    public void  before() throws IOException {
        String resource="SqlMapConfig.xml";
        InputStream in = Resources.getResourceAsStream(resource);
        sqlSessionFactory= new SqlSessionFactoryBuilder().build(in);
    }
    //一级缓存测试
    @Test
    public  void findOrderAndDetail() throws Exception {
        SqlSession sqlSession=sqlSessionFactory.openSession();
        //第一次查询
        UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
        User user= userMapper.getUserById(1);
        System.out.println(user.getUsername());
        //第二次查询(没有关闭sqlsession)
        User user2= userMapper.getUserById(1);
        System.out.println(user2.getUsername());
    }


}


3、mybatis二级缓存

是mapper级别缓存,垮sqlsession的。同一个namespace命名空间的缓存,以命名空间为单位来创建缓存结构。

如果从二级缓存没有取到,再从一级缓存中找,如果一级缓存也没有,从数据库查询。

map<keyvalue>


配置二级缓存:

3.1、打开总开关

 二级缓存

描述

允许值

默认值

cacheEnabled

对在此配置文件下的所有cache 进行全局性开/关设置。

true false

true

在setting里面增加
        <!-- 二级缓存总开关 -->
        <setting name="cacheEnabled" value="true"/>

3.2、mapper里面添加cache

要在你的Mapper映射文件中添加一行:  <cache /> ,表示此mapper开启二级缓存。在mapper下面增加

    <!--打开mapper二级缓存开关-->
    <cache/>



3.3、pojo中java对象需要实现序列化接口

public class User implements Serializable


3.4、测试结果

<span style="font-size:12px;">package com.ycy.mybatis.test;

import com.ycy.mybatis.dao.OrdersCustomMapper;
import com.ycy.mybatis.dao.UserMapper;
import com.ycy.mybatis.dao.impl.UserMappermpl;
import com.ycy.mybatis.module.Orders;
import com.ycy.mybatis.module.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * Created by Administrator on 2015/8/31 0031.
 */
public class MybatisTest9 {
    private SqlSessionFactory sqlSessionFactory = null;
    @Before
    public void  before() throws IOException {
        String resource="SqlMapConfig.xml";
        InputStream in = Resources.getResourceAsStream(resource);
        sqlSessionFactory= new SqlSessionFactoryBuilder().build(in);
    }
    //一级缓存测试
    @Test
    public  void findOrderAndDetail() throws Exception {
        SqlSession sqlSession=sqlSessionFactory.openSession();
        //第一次查询
        UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
        User user= userMapper.getUserById(1);
        System.out.println(user.getUsername());
        //第二次查询(没有关闭sqlsession)
        User user2= userMapper.getUserById(1);
        System.out.println(user2.getUsername());
    }
    //二级缓存测试
    @Test
    public  void cache2() throws Exception {
        SqlSession sqlSession=sqlSessionFactory.openSession();
        SqlSession sqlSession2=sqlSessionFactory.openSession();
        UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
        UserMapper userMapper2=sqlSession2.getMapper(UserMapper.class);

        //第一次查询
        User user= userMapper.getUserById(1);
        System.out.println(user.getUsername());
        sqlSession.close();

        //第二次查询()
        User user2= userMapper2.getUserById(1);
        System.out.println(user2.getUsername());

        sqlSession2.close();
    }

}</span>

我们主要看:这个表示缓存变为2次用了1次,0.5证明我们的缓存成功了哦

输出结果:

Cache Hit Ratio [com.ycy.mybatis.dao.UserMapper]: 0.5

17:35:47.516 [main] DEBUG com.ycy.mybatis.dao.UserMapper - Cache Hit Ratio [com.ycy.mybatis.dao.UserMapper]: 0.0
17:35:47.536 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Opening JDBC Connection
17:35:47.912 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource - Created connection 1674518905.
17:35:47.913 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@63cf2179]
17:35:47.917 [main] DEBUG com.ycy.mybatis.dao.UserMapper.getUserById - ==>  Preparing: SELECT * FROM USER WHERE id=? 
17:35:47.998 [main] DEBUG com.ycy.mybatis.dao.UserMapper.getUserById - ==> Parameters: 1(Integer)
17:35:48.024 [main] DEBUG com.ycy.mybatis.dao.UserMapper.getUserById - <==      Total: 1
王五
17:35:48.031 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@63cf2179]
17:35:48.032 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@63cf2179]
17:35:48.032 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource - Returned connection 1674518905 to pool.
17:35:48.033 [main] DEBUG com.ycy.mybatis.dao.UserMapper - Cache Hit Ratio [com.ycy.mybatis.dao.UserMapper]: 0.5
王五

3.5、二级缓存关闭

对于变化频率较高的sql,需要禁用二级缓存:(因为变得我们记住它没得意思)

在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认情况是true,即该sql使用二级缓存。

<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">

    <select id="getUserById" parameterType="int" resultType="User" useCache="false">
         SELECT  * FROM USER WHERE id=#{id}
        </select>
不测试了哦,自己测试

如果你关闭之后去测试没有下面一行:

Cache Hit Ratio [com.ycy.mybatis.dao.UserMapper]: 0.0

3.6、刷新二级缓存

如果sqlsession操作commit操作,对二级缓存进行刷新(全局清空)。

设置statementflushCache是否刷新缓存,默认值是true

 <!--新增用户-->
    <insert id="insertUser" parameterType="User" flushCache="true">
        <!--插入值之后返回主键值-->
        <selectKey resultType="int" order="AFTER" keyProperty="id">
            SELECT LAST_INSERT_ID()
        </selectKey>
        INSERT  INTO USER  (username,birthday,sex,address) VALUES (#{username},#{birthday},#{sex},#{address})
    </insert>


不测试了哦,自己测试

你刷新之后,缓存依旧为0.0:

Cache Hit Ratio [com.ycy.mybatis.dao.UserMapper]: 0.0

3.7、 mybatiscache参数(了解)

 

mybatiscache参数只适用于mybatis维护缓存。

 

flushInterval:(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。

size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的可用内存资源数目。默认值是1024

readOnly(只读)属性可以被设置为truefalse。只读的缓存会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false

 

如下例子:

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

这个更高级的配置创建了一个 FIFO 缓存,并每隔 60 秒刷新,存数结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会导致冲突。可用的收回策略有默认的是 LRU:

1. LRU  最近最少使用的:移除最长时间不被使用的对象。

2. FIFO  先进先出:按对象进入缓存的顺序来移除它们。

3. SOFT  软引用:移除基于垃圾回收器状态和软引用规则的对象。

4. WEAK  弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。



目录
相关文章
|
1月前
|
缓存 NoSQL Java
Mybatis学习:Mybatis缓存配置
MyBatis缓存配置包括一级缓存(事务级)、二级缓存(应用级)和三级缓存(如Redis,跨JVM)。一级缓存自动启用,二级缓存需在`mybatis-config.xml`中开启并配置映射文件或注解。集成Redis缓存时,需添加依赖、配置Redis参数并在映射文件中指定缓存类型。适用于查询为主的场景,减少增删改操作,适合单表操作且表间关联较少的业务。
|
3月前
|
SQL Java 数据库连接
【MyBatisPlus·最新教程】包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段
MyBatis-Plus是一个MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。本文讲解了最新版MP的使用教程,包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段等核心功能。
【MyBatisPlus·最新教程】包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段
|
3月前
|
SQL 缓存 Java
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
本文详细介绍了MyBatis的各种常见用法MyBatis多级缓存、逆向工程、分页插件 包括获取参数值和结果的各种情况、自定义映射resultMap、动态SQL
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
|
3月前
|
SQL 存储 数据库
深入理解@TableField注解的使用-MybatisPlus教程
`@TableField`注解在MyBatis-Plus中是一个非常灵活和强大的工具,能够帮助开发者精细控制实体类与数据库表字段之间的映射关系。通过合理使用 `@TableField`注解,可以实现字段名称映射、自动填充、条件查询以及自定义类型处理等高级功能。这些功能在实际开发中,可以显著提高代码的可读性和维护性。如果需要进一步优化和管理你的MyBatis-Plus应用程
306 3
|
4月前
|
缓存 Java 数据库连接
使用MyBatis缓存的简单案例
MyBatis 是一种流行的持久层框架,支持自定义 SQL 执行、映射及复杂查询。本文介绍了如何在 Spring Boot 项目中集成 MyBatis 并实现一级和二级缓存,以提高查询性能,减少数据库访问。通过具体的电商系统案例,详细讲解了项目搭建、缓存配置、实体类创建、Mapper 编写、Service 层实现及缓存测试等步骤。
|
4月前
|
SQL 缓存 Java
JVM知识体系学习三:class文件初始化过程、硬件层数据一致性(硬件层)、缓存行、指令乱序执行问题、如何保证不乱序(volatile等)
这篇文章详细介绍了JVM中类文件的初始化过程、硬件层面的数据一致性问题、缓存行和伪共享、指令乱序执行问题,以及如何通过`volatile`关键字和`synchronized`关键字来保证数据的有序性和可见性。
67 3
|
19天前
|
缓存 NoSQL 中间件
Redis,分布式缓存演化之路
本文介绍了基于Redis的分布式缓存演化,探讨了分布式锁和缓存一致性问题及其解决方案。首先分析了本地缓存和分布式缓存的区别与优劣,接着深入讲解了分布式远程缓存带来的并发、缓存失效(穿透、雪崩、击穿)等问题及应对策略。文章还详细描述了如何使用Redis实现分布式锁,确保高并发场景下的数据一致性和系统稳定性。最后,通过双写模式和失效模式讨论了缓存一致性问题,并提出了多种解决方案,如引入Canal中间件等。希望这些内容能为读者在设计分布式缓存系统时提供有价值的参考。感谢您的阅读!
110 6
Redis,分布式缓存演化之路
|
2月前
|
存储 缓存 NoSQL
解决Redis缓存数据类型丢失问题
解决Redis缓存数据类型丢失问题
194 85
|
1月前
|
存储 缓存 NoSQL
云端问道21期方案教学-应对高并发,利用云数据库 Tair(兼容 Redis®*)缓存实现极速响应
云端问道21期方案教学-应对高并发,利用云数据库 Tair(兼容 Redis®*)缓存实现极速响应
|
1月前
|
缓存 NoSQL 关系型数据库
云端问道21期实操教学-应对高并发,利用云数据库 Tair(兼容 Redis®)缓存实现极速响应
本文介绍了如何通过云端问道21期实操教学,利用云数据库 Tair(兼容 Redis®)缓存实现高并发场景下的极速响应。主要内容分为四部分:方案概览、部署准备、一键部署和完成及清理。方案概览中,展示了如何使用 Redis 提升业务性能,降低响应时间;部署准备介绍了账号注册与充值步骤;一键部署详细讲解了创建 ECS、RDS 和 Redis 实例的过程;最后,通过对比测试验证了 Redis 缓存的有效性,并指导用户清理资源以避免额外费用。