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  弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。



目录
相关文章
|
17天前
|
存储 缓存 芯片
让星星⭐月亮告诉你,当我们在说CPU一级缓存二级缓存三级缓存的时候,我们到底在说什么?
本文介绍了CPU缓存的基本概念和作用,以及不同级别的缓存(L1、L2、L3)的特点和工作原理。CPU缓存是CPU内部的存储器,用于存储RAM中的数据和指令副本,以提高数据访问速度,减少CPU与RAM之间的速度差异。L1缓存位于处理器内部,速度最快;L2缓存容量更大,但速度稍慢;L3缓存容量最大,由所有CPU内核共享。文章还对比了DRAM和SRAM两种内存类型,解释了它们在计算机系统中的应用。
54 1
|
2月前
|
缓存 Java 数据库连接
mybatis复习05,mybatis的缓存机制(一级缓存和二级缓存及第三方缓存)
文章介绍了MyBatis的缓存机制,包括一级缓存和二级缓存的配置和使用,以及如何整合第三方缓存EHCache。详细解释了一级缓存的生命周期、二级缓存的开启条件和配置属性,以及如何通过ehcache.xml配置文件和logback.xml日志配置文件来实现EHCache的整合。
mybatis复习05,mybatis的缓存机制(一级缓存和二级缓存及第三方缓存)
|
12天前
|
缓存 Java 数据库连接
使用MyBatis缓存的简单案例
MyBatis 是一种流行的持久层框架,支持自定义 SQL 执行、映射及复杂查询。本文介绍了如何在 Spring Boot 项目中集成 MyBatis 并实现一级和二级缓存,以提高查询性能,减少数据库访问。通过具体的电商系统案例,详细讲解了项目搭建、缓存配置、实体类创建、Mapper 编写、Service 层实现及缓存测试等步骤。
|
17天前
|
SQL 缓存 Java
JVM知识体系学习三:class文件初始化过程、硬件层数据一致性(硬件层)、缓存行、指令乱序执行问题、如何保证不乱序(volatile等)
这篇文章详细介绍了JVM中类文件的初始化过程、硬件层面的数据一致性问题、缓存行和伪共享、指令乱序执行问题,以及如何通过`volatile`关键字和`synchronized`关键字来保证数据的有序性和可见性。
18 3
|
3月前
|
缓存 JavaScript
Vue学习之--------编程式路由导航、缓存路由组件、新的钩子函数(4)(2022/9/5)
这篇文章介绍了Vue中编程式路由导航的方法,包括使用`$router.push`、`$router.replace`、`$router.forward`、`$router.back`和`$router.go`进行路由跳转和历史记录操作,以及如何利用`<keep-alive>`组件缓存路由组件,和Vue Router新增的两个生命周期钩子`activated`和`deactivated`的用法及其在项目中的应用和测试结果。
Vue学习之--------编程式路由导航、缓存路由组件、新的钩子函数(4)(2022/9/5)
|
4月前
|
SQL 缓存 Java
【面试官】Mybatis缓存有什么问题吗?
面试官:你说下对MyBatis的理解?面试官:那SqlSession知道吧?面试官:Mybatis的缓存有哪几种?面试官:那Mybatis缓存有什么问题吗?面试官:Mybatis分页插件是怎么
【面试官】Mybatis缓存有什么问题吗?
|
4月前
|
缓存 算法 Java
关于MyBatis的缓存详解
MyBatis 的缓存机制非常灵活,可以通过简单的配置来满足不同的性能需求。合理地使用缓存可以显著提高应用程序的性能,尤其是在处理大量数据库查询时。然而,开发者需要注意缓存的一致性和并发问题,特别是在使用可读写缓存时。
|
3月前
|
存储 缓存 Java
|
26天前
|
存储 缓存 NoSQL
数据的存储--Redis缓存存储(一)
数据的存储--Redis缓存存储(一)
60 1
|
26天前
|
存储 缓存 NoSQL
数据的存储--Redis缓存存储(二)
数据的存储--Redis缓存存储(二)
37 2
数据的存储--Redis缓存存储(二)