mybatis一级缓存,mybatis二级缓存,mybatis缓存失效(代码片段)

蕃薯耀 蕃薯耀     2022-12-01     308

关键词:

Mybatis 一级缓存,Mybatis 二级缓存,Mybatis 缓存失效

 

================================

©Copyright 蕃薯耀 2021-06-24

https://www.cnblogs.com/fanshuyao/

 

一、SpringBoot整合Mybatis

1、pom.xml引入依赖(基于SpringBoot:2.3.12.RELEASE)

<properties>
    <!-- JDK版本 -->
    <java.version>1.8</java.version>
    <!-- 构建时编码 -->    
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <!-- 输出时编码 -->
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    
    <!-- 5.1.49 -->
    <!-- 8.0.25 -->
    <mysql.version>5.1.49</mysql.version>
</properties>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- 2.2.0 -->
<!-- 2.1.4 -->
<!-- 
master(2.2.x) : MyBatis 3.5+, MyBatis-Spring 2.0+(2.0.6+ recommended), Java 8+ and Spring Boot 2.5+
2.1.x : MyBatis 3.5+, MyBatis-Spring 2.0+(2.0.6+ recommended), Java 8+ and Spring Boot 2.1-2.4

mybatis-spring-boot-starter自动配置:
Autodetect an existing DataSource
Will create and register an instance of a SqlSessionFactory passing that DataSource as an input using the SqlSessionFactoryBean
Will create and register an instance of a SqlSessionTemplate got out of the SqlSessionFactory
Auto-scan your mappers, link them to the SqlSessionTemplate and register them to Spring context so they can be injected into your beans

翻译:
自动检测现有数据源
将创建和注册 SqlSessionFactory 的实例,使用 SqlSessionFactoryBean 将该数据源作为输入传递
将创建并注册一个从 SqlSessionFactory 中得到的 SqlSessionTemplate 的实例
自动扫描您的映射器,将它们链接到 SqlSessionTemplate 并将它们注册到 Spring 上下文,以便它们可以注入到您的 bean 中
 -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.4</version>
</dependency>


<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

 

 

2、application.properties配置文件修改

#数据库连接配置
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql://localhost:3307/db?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&pinGlobalTxToPhysicalConnection=true&autoReconnect=true
spring.datasource.driver-class-name=com.mysql.jdbc.Driver


#Mybatis配置
#详细配置项见:
#https://mybatis.org/mybatis-3/configuration.html#settings
#扫描实体包作为别名
mybatis.type-aliases-package=com.lqy.entity
#驼峰命名
mybatis.configuration.map-underscore-to-camel-case=true
#启动全局缓存,默认是true
mybatis.configuration.cache-enabled=true
#启动懒加载
mybatis.configuration.lazy-loading-enabled=true
#打印日志
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

 

3、启动类加上@MapperScan注解,自动扫描Mybatis Mapper包

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.lqy.mapper")
public class MybatisCacheApplication 

    public static void main(String[] args) 
        SpringApplication.run(MybatisCacheApplication.class, args);
    



Mybatis使用@MapperScan注解后,Mapper文件不需要再加@Mapper注解

 

 

4、创建Mapper接口

import org.apache.ibatis.annotations.Select;

import com.lqy.entity.Student;

public interface StudentMapper 

    @Select("select * from student where id = #id")
    public Student get(Long id);
    

 

 

5、测试SpringBoot整合Mybatis

//slf4j
private Logger log =  LoggerFactory.getLogger(MybatisCacheController.class);

@Resource
private StudentMapper studentMapper;

@RequestMapping("/db/id")
public Result db(@PathVariable("id") Long id) 
    Student student = studentMapper.get(id);
    log.info("student is ", student);
    return Result.ok(student);

 

 

 

二、Mybatis 一级缓存

1、Mybatis同一个会话(sqlSession),一级缓存生效

/**
 * Mybatis同一个会话(sqlSession),测试一级缓存
 *  结论:
 * Mybatis同一个会话,两次查询同一条数据,只打印了一条sql查询语句,一级缓存生效
 * @param id
 * @return
 */
@RequestMapping("/sameSession/id")
public Result sameSession(@PathVariable("id") Long id) 
    
    SqlSession sqlSession = sqlSessionFactory.openSession();
    
    StudentMapper stuMapper1  =sqlSession.getMapper(StudentMapper.class);
    StudentMapper stuMapper2  =sqlSession.getMapper(StudentMapper.class);
    
    Student student1 = stuMapper1.get(id);
    log.info("stuMapper1 student is ", student1);
    
    
    Student student2 = stuMapper2.get(id);
    log.info("stuMapper2 student is ", student2);
    
    sqlSession.close();
    
    return Result.ok(student1);

 

2021-06-23 11:13:03.125  INFO 9084 --- [io-4000-exec-10] o.a.c.c.C.[.[localhost].[/mybatisCache]  : Initializing Spring DispatcherServlet \'dispatcherServlet\'
2021-06-23 11:13:03.126  INFO 9084 --- [io-4000-exec-10] o.s.web.servlet.DispatcherServlet        : Initializing Servlet \'dispatcherServlet\'
2021-06-23 11:13:03.135  INFO 9084 --- [io-4000-exec-10] o.s.web.servlet.DispatcherServlet        : Completed initialization in 9 ms
2021-06-23 11:13:03.137  INFO 9084 --- [io-4000-exec-10] com.zaxxer.hikari.HikariDataSource       : HikariPool-3 - Starting...
2021-06-23 11:13:03.143  INFO 9084 --- [io-4000-exec-10] com.zaxxer.hikari.HikariDataSource       : HikariPool-3 - Start completed.
==>  Preparing: select * from student where id = ?
==> Parameters: 1(Long)
<==    Columns: id, stu_no, stu_name, age, clazz_id, create_time, remark
<==        Row: 1, 1, 学生一, null, null, 2021-04-26 19:01:29.0, null
<==      Total: 1
2021-06-23 11:13:03.146  INFO 9084 --- [io-4000-exec-10] c.lqy.controller.MybatisCacheController  : stuMapper1 student is com.lqy.entity.Student@2a61ea98
2021-06-23 11:13:03.146  INFO 9084 --- [io-4000-exec-10] c.lqy.controller.MybatisCacheController  : stuMapper2 student is com.lqy.entity.Student@2a61ea98

 

 

2、Mybatis不是同一个会话(sqlSession),一级缓存不生效

/**
 * Mybatis不是同一个会话(sqlSession),测试一级缓存
 * 结论:
 * Mybatis不是同一个会话,两次查询同一条数据,打印了两条sql查询语句,一级缓存不生效
 * @param id
 * @return
 */
@RequestMapping("/notSameSession/id")
public Result notSameSession(@PathVariable("id") Long id) 
    
    SqlSession sqlSession1 = sqlSessionFactory.openSession();
    SqlSession sqlSession2 = sqlSessionFactory.openSession();
    
    StudentMapper stuMapper1  =sqlSession1.getMapper(StudentMapper.class);
    StudentMapper stuMapper2  =sqlSession2.getMapper(StudentMapper.class);
    
    Student student = stuMapper1.get(id);
    log.info("stuMapper1 student is ", student);
    sqlSession1.close();
    
    
    Student student2 = stuMapper2.get(id);
    log.info("stuMapper2 student is ", student2);
    
    sqlSession2.close();
    
    return Result.ok(student);

 

2021-06-23 11:30:31.334  INFO 188 --- [nio-4000-exec-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-2 - Starting...
2021-06-23 11:30:31.339  INFO 188 --- [nio-4000-exec-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-2 - Start completed.
JDBC Connection [HikariProxyConnection@1835684313 wrapping com.mysql.jdbc.JDBC4Connection@4d739d17] will not be managed by Spring
==>  Preparing: select * from student where id = ?
==> Parameters: 1(Long)
<==    Columns: id, stu_no, stu_name, age, clazz_id, create_time, remark
<==        Row: 1, 1, 学生一, null, null, 2021-04-26 19:01:29.0, null
<==      Total: 1
2021-06-23 11:30:31.348  INFO 188 --- [nio-4000-exec-1] c.lqy.controller.MybatisCacheController  : =====stuMapper1 student is com.lqy.entity.Student@e4441a0
JDBC Connection [HikariProxyConnection@1594814042 wrapping com.mysql.jdbc.JDBC4Connection@4d739d17] will not be managed by Spring
==>  Preparing: select * from student where id = ?
==> Parameters: 1(Long)
<==    Columns: id, stu_no, stu_name, age, clazz_id, create_time, remark
<==        Row: 1, 1, 学生一, null, null, 2021-04-26 19:01:29.0, null
<==      Total: 1
2021-06-23 11:30:31.353  INFO 188 --- [nio-4000-exec-1] c.lqy.controller.MybatisCacheController  : =====stuMapper2 student is com.lqy.entity.Student@4f28bd07

 

 

3、Mybatis同一个会话(sqlSession),两次查询之间做了更新操作(新增、删除、修改),一级缓存不生效(发送了2次查询sql)

/**
 * Mybatis同一个会话(sqlSession),两次查询之间做了更新操作(新增、删除、修改),一级缓存不生效
 * @param id
 * @return
 */
@RequestMapping("/sameSessionUpdate/id")
public Result sameSessionUpdate(@PathVariable("id") Long id) 
    
    SqlSession sqlSession = sqlSessionFactory.openSession();
    
    StudentMapper stuMapper1  =sqlSession.getMapper(StudentMapper.class);
    StudentMapper stuMapper2  =sqlSession.getMapper(StudentMapper.class);
    StudentMapper stuMapper3  =sqlSession.getMapper(StudentMapper.class);
    
    Student student1 = stuMapper1.get(id);
    log.info(logPrefix + "stuMapper1 student is ", student1);
    
    //两次查询之间做了更新操作(新增、删除、修改)
    stuMapper3.update(id);
    
    Student student2 = stuMapper2.get(id);
    log.info(logPrefix + "stuMapper2 student is ", student2);
    
    sqlSession.close();
    
    return Result.ok(student1);

 

JDBC Connection [HikariProxyConnection@1830365917 wrapping com.mysql.jdbc.JDBC4Connection@1fa708f1] will not be managed by Spring
==>  Preparing: select * from student where id = ?
==> Parameters: 1(Long)
<==    Columns: id, stu_no, stu_name, age, clazz_id, create_time, remark
<==        Row: 1, 1, 学生一, null, null, 2021-04-26 19:01:29.0, 1
<==      Total: 1
2021-06-23 14:34:15.775  INFO 3228 --- [nio-4000-exec-2] c.lqy.controller.MybatisCacheController  : =====stuMapper1 student is com.lqy.entity.Student@67e141ad
==>  Preparing: update student set remark = ? where id = ?
==> Parameters: 1(Long), 1(Long)
<==    Updates: 1
==>  Preparing: select * from student where id = ?
==> Parameters: 1(Long)
<==    Columns: id, stu_no, stu_name, age, clazz_id, create_time, remark
<==        Row: 1, 1, 学生一, null, null, 2021-04-26 19:01:29.0, 1
<==      Total: 1
2021-06-23 14:34:15.818  INFO 3228 --- [nio-4000-exec-2] c.lqy.controller.MybatisCacheController  : =====stuMapper2 student is com.lqy.entity.Student@42cc3c7a

 

4、 Mybatis同一个会话(sqlSession),手动清除缓存后的一级缓存不生效。因为手动清除缓存已经没有缓存:sqlSession.clearCache()

/**
 * Mybatis同一个会话(sqlSession),手动清除缓存后的一级缓存不生效。因为手动清除缓存已经没有缓存:sqlSession.clearCache()
 *  结论:
 * @param id
 * @return
 */
@RequestMapping("/sameSessionClearCache/id")
public Result sameSessionClearCache(@PathVariable("id") Long id) 
    
    SqlSession sqlSession = sqlSessionFactory.openSession();
    
    StudentMapper stuMapper1  =sqlSession.getMapper(StudentMapper.class);
    StudentMapper stuMapper2  =sqlSession.getMapper(StudentMapper.class);
    
    Student student1 = stuMapper1.get(id);
    log.info(logPrefix + "stuMapper1 student is ", student1);
    
    sqlSession.clearCache();
    
    Student student2 = stuMapper2.get(id);
    log.info(logPrefix + "stuMapper2 student is ", student2);
    
    sqlSession.close();
    
    return Result.ok(student1);

 

2021-06-23 14:38:52.228  INFO 3228 --- [nio-4000-exec-4] com.zaxxer.hikari.HikariDataSource       : HikariPool-4 - Starting...
2021-06-23 14:38:52.235  INFO 3228 --- [nio-4000-exec-4] com.zaxxer.hikari.HikariDataSource       : HikariPool-4 - Start completed.
JDBC Connection [HikariProxyConnection@1539770887 wrapping com.mysql.jdbc.JDBC4Connection@3975b4fb] will not be managed by Spring
==>  Preparing: select * from student where id = ?
==> Parameters: 1(Long)
<==    Columns: id, stu_no, stu_name, age, clazz_id, create_time, remark
<==        Row: 1, 1, 学生一, null, null, 2021-04-26 19:01:29.0, 1
<==      Total: 1
2021-06-23 14:38:52.240  INFO 3228 --- [nio-4000-exec-4] c.lqy.controller.MybatisCacheController  : =====stuMapper1 student is com.lqy.entity.Student@528bc92f
==>  Preparing: select * from student where id = ?
==> Parameters: 1(Long)
<==    Columns: id, stu_no, stu_name, age, clazz_id, create_time, remark
<==        Row: 1, 1, 学生一, null, null, 2021-04-26 19:01:29.0, 1
<==      Total: 1
2021-06-23 14:38:52.242  INFO 3228 --- [nio-4000-exec-4] c.lqy.controller.MybatisCacheController  : =====stuMapper2 student is com.lqy.entity.Student@7dea6ddf

 

 

5、总结:
Mybatis 一级缓存(会话级别缓存:sqlSession)默认是开启的。

Mybatis 一级缓存失效的情况:
(1)、非同一个sqlSession(两个不同的sqlSession)
(2)、同一个sqlSession,查询条件不同(查询条件不同,相应的数据还没有放到缓存)
(3)、同一个sqlSession,两次查询之间做了更新操作(新增、删除、修改)
(4)、同一个sqlSession,两次查询之间做了缓存清除:sqlSession.clearCache()

 

 

 

三、Mybatis 二级缓存

Mybatis 二级缓存启用:
(1)、需要开启全局二级缓存:在application.properties文件配置:mybatis.configuration.cache-enabled=true,cache-enabled默认是开启的,即可以配置也可以不配置

(2)、需要在XxxMapper的接口类上加上注解:@CacheNamespace,表示该Mapper开启二级缓存
示例:

@CacheNamespace
public interface StudentMapper 

(3)、实体bean要实现Serializable接口

 

 

1、Mybatis同一个会话(sqlSession),两次查询同一条数据,只打印了一条sql查询语句,二级缓存生效
和一级缓存的区别是:开启二级缓存后 ,会有缓存命中率的打印(Cache Hit Ratio)

/**
 * Mybatis同一个会话(sqlSession),分别请求两次:
 * 第一次请求,两次查询同一条数据,只打印了一条sql查询语句,一级缓存生效
 * 第二次请求,两次查询同一条数据,没有打印sql查询语句,二级缓存生效
 * @param id
 * @return
 */
@RequestMapping("/sameSession/id")
public Result sameSession(@PathVariable("id") Long id) 
    
    SqlSession sqlSession = sqlSessionFactory.openSession();
    
    StudentMapper stuMapper1  =sqlSession.getMapper(StudentMapper.class);
    StudentMapper stuMapper2  =sqlSession.getMapper(StudentMapper.class);
    
    Student student1 = stuMapper1.get(id);
    log.info(logPrefix + "stuMapper1 student is ", student1);
    
    
    Student student2 = stuMapper2.get(id);
    log.info(logPrefix + "stuMapper2 student is ", student2);
    
    sqlSession.close();
    
    return Result.ok(student1);

 

第一次查询(一级缓存生效,发送了一次sql查询,二级缓存未命中(还没有二级缓存数据,只有在sqlSession关闭后才放到二级缓存)):
Cache Hit Ratio [com.lqy.mapper.StudentMapper]: 0.0
2021-06-23 15:15:15.752  INFO 10808 --- [nio-4000-exec-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2021-06-23 15:15:16.032  INFO 10808 --- [nio-4000-exec-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
JDBC Connection [HikariProxyConnection@1253127447 wrapping com.mysql.jdbc.JDBC4Connection@3072075a] will not be managed by Spring
==>  Preparing: select * from student where id = ?
==> Parameters: 1(Long)
<==    Columns: id, stu_no, stu_name, age, clazz_id, create_time, remark
<==        Row: 1, 1, 学生一, null, null, 2021-04-26 19:01:29.0, 1
<==      Total: 1
2021-06-23 15:15:16.072  INFO 10808 --- [nio-4000-exec-1] c.lqy.controller.SecondCacheController   : =====stuMapper1 student is com.lqy.entity.Student@235995b6
Cache Hit Ratio [com.lqy.mapper.StudentMapper]: 0.0
2021-06-23 15:15:16.072  INFO 10808 --- [nio-4000-exec-1] c.lqy.controller.SecondCacheController   : =====stuMapper2 student is com.lqy.entity.Student@235995b6


第二次查询(二级缓存已经命中,没有发送sql查询):
As you are using functionality that deserializes object streams, it is recommended to define the JEP-290 serial filter. Please refer to https://docs.oracle.com/pls/topic/lookup?ctx=javase15&id=GUID-8296D8E8-2B93-4B9A-856E-0A65AF9B8C66
Cache Hit Ratio [com.lqy.mapper.StudentMapper]: 0.3333333333333333
2021-06-23 15:20:11.201  INFO 10808 --- [nio-4000-exec-4] c.lqy.controller.SecondCacheController   : =====stuMapper1 student is com.lqy.entity.Student@3890ca0c
Cache Hit Ratio [com.lqy.mapper.StudentMapper]: 0.5
2021-06-23 15:20:11.201  INFO 10808 --- [nio-4000-exec-4] c.lqy.controller.SecondCacheController   : =====stuMapper2 student is com.lqy.entity.Student@61e9e758

 

 

2、Mybatis不是一个会话(sqlSession),两次查询同一条数据,只打印了一条sql查询语句,第二次查询从二缓存命中,二级缓存生效

/**
 * Mybatis不是同一个会话(sqlSession)
 * 第一次请求,两次查询同一条数据,第一次查询打印了一条sql查询语句(一、二级缓存未生效),第二次查询(在第一次查询sqlSession关闭后,数据放到二级缓存),二缓存命中(一级缓存不生效),二级缓存生效
 * 第二次请求,两次查询同一条数据,没有打印sql查询语句,二级缓存生效
 * @param id
 * @return
 */
@RequestMapping("/notSameSession/id")
public Result notSameSession(@PathVariable("id") Long id) 
    
    SqlSession sqlSession1 = sqlSessionFactory.openSession();
    SqlSession sqlSession2 = sqlSessionFactory.openSession();
    
    StudentMapper stuMapper1  =sqlSession1.getMapper(StudentMapper.class);
    StudentMapper stuMapper2  =sqlSession2.getMapper(StudentMapper.class);
    
    Student student = stuMapper1.get(id);
    log.info(logPrefix + "stuMapper1 student is ", student);
    sqlSession1.close();
    
    
    Student student2 = stuMapper2.get(id);
    log.info(logPrefix + "stuMapper2 student is ", student2);
    
    sqlSession2.close();
    
    return Result.ok(student);

 

第一次请求:
Cache Hit Ratio [com.lqy.mapper.StudentMapper]: 0.0
2021-06-23 15:33:33.868  INFO 1120 --- [nio-4000-exec-5] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2021-06-23 15:33:34.188  INFO 1120 --- [nio-4000-exec-5] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
JDBC Connection [HikariProxyConnection@1023753071 wrapping com.mysql.jdbc.JDBC4Connection@2ca9d629] will not be managed by Spring
==>  Preparing: select * from student where id = ?
==> Parameters: 1(Long)
<==    Columns: id, stu_no, stu_name, age, clazz_id, create_time, remark
<==        Row: 1, 1, 学生一, null, null, 2021-04-26 19:01:29.0, 1
<==      Total: 1
2021-06-23 15:33:34.229  INFO 1120 --- [nio-4000-exec-5] c.lqy.controller.SecondCacheController   : =====stuMapper1 student is com.lqy.entity.Student@48b64b58
As you are using functionality that deserializes object streams, it is recommended to define the JEP-290 serial filter. Please refer to https://docs.oracle.com/pls/topic/lookup?ctx=javase15&id=GUID-8296D8E8-2B93-4B9A-856E-0A65AF9B8C66
Cache Hit Ratio [com.lqy.mapper.StudentMapper]: 0.5
2021-06-23 15:33:34.238  INFO 1120 --- [nio-4000-exec-5] c.lqy.controller.SecondCacheController   : =====stuMapper2 student is com.lqy.entity.Student@a654eb8


第二次请求:
Cache Hit Ratio [com.lqy.mapper.StudentMapper]: 0.6666666666666666
2021-06-23 15:36:19.272  INFO 1120 --- [nio-4000-exec-9] c.lqy.controller.SecondCacheController   : =====stuMapper1 student is com.lqy.entity.Student@13a150d5
Cache Hit Ratio [com.lqy.mapper.StudentMapper]: 0.75
2021-06-23 15:36:19.273  INFO 1120 --- [nio-4000-exec-9] c.lqy.controller.SecondCacheController   : =====stuMapper2 student is com.lqy.entity.Student@1d66bcd1

 

3、Mybatis同一个会话(sqlSession),两次查询之间做了更新操作(新增、删除、修改),一、二级缓存都不生效(发送了2次查询sql)

/**
 * Mybatis同一个会话(sqlSession),两次查询之间做了更新操作(新增、删除、修改),一、二级缓存都不生效(发送了2次查询sql)
 * @param id
 * @return
 */
@RequestMapping("/sameSessionUpdate/id")
public Result sameSessionUpdate(@PathVariable("id") Long id) 
    
    SqlSession sqlSession = sqlSessionFactory.openSession();
    
    StudentMapper stuMapper1  =sqlSession.getMapper(StudentMapper.class);
    StudentMapper stuMapper2  =sqlSession.getMapper(StudentMapper.class);
    StudentMapper stuMapper3  =sqlSession.getMapper(StudentMapper.class);
    
    Student student1 = stuMapper1.get(id);
    log.info(logPrefix + "stuMapper1 student is ", student1);
    
    //两次查询之间做了更新操作(新增、删除、修改)
    stuMapper3.update(id);
    
    Student student2 = stuMapper2.get(id);
    log.info(logPrefix + "stuMapper2 student is ", student2);
    
    sqlSession.close();
    
    return Result.ok(student1);

 

Cache Hit Ratio [com.lqy.mapper.StudentMapper]: 0.0
2021-06-23 15:39:44.807  INFO 1120 --- [nio-4000-exec-6] com.zaxxer.hikari.HikariDataSource       : HikariPool-2 - Starting...
2021-06-23 15:39:44.813  INFO 1120 --- [nio-4000-exec-6] com.zaxxer.hikari.HikariDataSource       : HikariPool-2 - Start completed.
JDBC Connection [HikariProxyConnection@253872058 wrapping com.mysql.jdbc.JDBC4Connection@698c372c] will not be managed by Spring
==>  Preparing: select * from student where id = ?
==> Parameters: 1(Long)
<==    Columns: id, stu_no, stu_name, age, clazz_id, create_time, remark
<==        Row: 1, 1, 学生一, null, null, 2021-04-26 19:01:29.0, 1
<==      Total: 1
2021-06-23 15:39:44.817  INFO 1120 --- [nio-4000-exec-6] c.lqy.controller.SecondCacheController   : =====stuMapper1 student is com.lqy.entity.Student@3a08debb
==>  Preparing: update student set remark = ? where id = ?
==> Parameters: 1(Long), 1(Long)
<==    Updates: 1
Cache Hit Ratio [com.lqy.mapper.StudentMapper]: 0.0
==>  Preparing: select * from student where id = ?
==> Parameters: 1(Long)
<==    Columns: id, stu_no, stu_name, age, clazz_id, create_time, remark
<==        Row: 1, 1, 学生一, null, null, 2021-04-26 19:01:29.0, 1
<==      Total: 1
2021-06-23 15:39:44.863  INFO 1120 --- [nio-4000-exec-6] c.lqy.controller.SecondCacheController   : =====stuMapper2 student is com.lqy.entity.Student@2231baba

 

 

4、Mybatis不是同一个会话(sqlSession),两次查询之间做了更新操作(新增、删除、修改),二级缓存生效
第一次请求:第一次查询发送了sql,一、二级缓存不生效。第二次查询,没有发送sql,二级缓存生效。
第二次请求:两次查询都没有发送sql,二级缓存生效

 

/**
 * Mybatis不是同一个会话(sqlSession),两次查询之间做了更新操作(新增、删除、修改),二级缓存生效
 * 第一次请求:第一次查询发送了sql,一、二级缓存不生效。第二次查询,没有发送sql,二级缓存生效
 * 第二次请求:两次查询都没有发送sql,二级缓存生效
 * @param id
 * @return
 */
@RequestMapping("/notSameSessionUpdate/id")
public Result notSameSessionUpdate(@PathVariable("id") Long id) 
    
    SqlSession sqlSession1 = sqlSessionFactory.openSession();
    SqlSession sqlSession2 = sqlSessionFactory.openSession();
    SqlSession sqlSession3 = sqlSessionFactory.openSession();
    
    StudentMapper stuMapper1  =sqlSession1.getMapper(StudentMapper.class);
    StudentMapper stuMapper2  =sqlSession2.getMapper(StudentMapper.class);
    StudentMapper stuMapper3  =sqlSession3.getMapper(StudentMapper.class);
    
    Student student1 = stuMapper1.get(id);
    log.info(logPrefix + "stuMapper1 student is ", student1);
    sqlSession1.close();
    
    //两次查询之间做了更新操作(新增、删除、修改)
    stuMapper3.update(id);
    sqlSession3.close();
    
    Student student2 = stuMapper2.get(id);
    log.info(logPrefix + "stuMapper2 student is ", student2);
    sqlSession2.close();
    
    return Result.ok(student1);

 

第一次请求:第一次查询发送了sql,一、二级缓存不生效。第二次查询,没有发送sql,二级缓存生效

Cache Hit Ratio [com.lqy.mapper.StudentMapper]: 0.0
2021-06-23 15:45:16.757  INFO 1120 --- [nio-4000-exec-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-4 - Starting...
2021-06-23 15:45:16.764  INFO 1120 --- [nio-4000-exec-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-4 - Start completed.
JDBC Connection [HikariProxyConnection@1475826374 wrapping com.mysql.jdbc.JDBC4Connection@2204d9a4] will not be managed by Spring
==>  Preparing: select * from student where id = ?
==> Parameters: 1(Long)
<==    Columns: id, stu_no, stu_name, age, clazz_id, create_time, remark
<==        Row: 1, 1, 学生一, null, null, 2021-04-26 19:01:29.0, 1
<==      Total: 1
2021-06-23 15:45:16.767  INFO 1120 --- [nio-4000-exec-1] c.lqy.controller.SecondCacheController   : =====stuMapper1 student is com.lqy.entity.Student@6a3d9b01
JDBC Connection [HikariProxyConnection@1775176572 wrapping com.mysql.jdbc.JDBC4Connection@2204d9a4] will not be managed by Spring
==>  Preparing: update student set remark = ? where id = ?
==> Parameters: 1(Long), 1(Long)
<==    Updates: 1
Cache Hit Ratio [com.lqy.mapper.StudentMapper]: 0.5
2021-06-23 15:45:16.811  INFO 1120 --- [nio-4000-exec-1] c.lqy.controller.SecondCacheController   : =====stuMapper2 student is com.lqy.entity.Student@207487b


第二次请求:两次查询都没有发送sql,二级缓存生效

Cache Hit Ratio [com.lqy.mapper.StudentMapper]: 0.6666666666666666
2021-06-23 15:45:50.022  INFO 1120 --- [nio-4000-exec-2] c.lqy.controller.SecondCacheController   : =====stuMapper1 student is com.lqy.entity.Student@311e46ff
JDBC Connection [HikariProxyConnection@1071230636 wrapping com.mysql.jdbc.JDBC4Connection@2204d9a4] will not be managed by Spring
==>  Preparing: update student set remark = ? where id = ?
==> Parameters: 1(Long), 1(Long)
<==    Updates: 1
Cache Hit Ratio [com.lqy.mapper.StudentMapper]: 0.75
2021-06-23 15:45:50.079  INFO 1120 --- [nio-4000-exec-2] c.lqy.controller.SecondCacheController   : =====stuMapper2 student is com.lqy.entity.Student@3d8e3c0a

 

 

5、Mybatis不是同一个会话(sqlSession),

第一次请求:一级缓存不生效(手动清除一级缓存:sqlSession.clearCache),二级缓存生效;

第二次请求:全部命中二级缓存,不发送sql,二级缓存生效

/**
 * Mybatis不是同一个会话(sqlSession)
 * 第一次请求:一级缓存不生效(手动清除一级缓存:sqlSession.clearCache),二级缓存生效
 * 第二次请求:全部命中二级缓存,不发送sql,二级缓存生效
 * @param id
 * @return
 */
@RequestMapping("/sameSessionClearCache/id")
public Result sameSessionClearCache(@PathVariable("id") Long id) 
    
    SqlSession sqlSession1 = sqlSessionFactory.openSession();
    SqlSession sqlSession3 = sqlSessionFactory.openSession();
    
    //都是sqlSession1
    StudentMapper stuMapper1  =sqlSession1.getMapper(StudentMapper.class);
    StudentMapper stuMapper2  =sqlSession1.getMapper(StudentMapper.class);
    
    //sqlSession3
    StudentMapper stuMapper3  =sqlSession3.getMapper(StudentMapper.class);
    
    Student student1 = stuMapper1.get(id);
    log.info(logPrefix + "stuMapper1 student is ", student1);
    
    //手动清除缓存
    sqlSession1.clearCache();//只清除一级缓存
    
    System.out.println(logSeparateLine);
    Student student2 = stuMapper2.get(id);
    log.info(logPrefix + "student2 student is ", student2);
    
    sqlSession1.close();
    
    
    System.out.println(logSeparateLine);
    Student student3 = stuMapper3.get(id);
    log.info(logPrefix + "student3 student is ", student3);
    
    sqlSession3.close();
    
    return Result.ok(student1);

 

第一次请求:
Cache Hit Ratio [com.lqy.mapper.StudentMapper]: 0.0
2021-06-23 16:03:26.164  INFO 1120 --- [nio-4000-exec-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-8 - Starting...
2021-06-23 16:03:26.170  INFO 1120 --- [nio-4000-exec-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-8 - Start completed.
JDBC Connection [HikariProxyConnection@276419536 wrapping com.mysql.jdbc.JDBC4Connection@20c9ed7d] will not be managed by Spring
==>  Preparing: select * from student where id = ?
==> Parameters: 1(Long)
<==    Columns: id, stu_no, stu_name, age, clazz_id, create_time, remark
<==        Row: 1, 1, 学生一, null, null, 2021-04-26 19:01:29.0, 1
<==      Total: 1
2021-06-23 16:03:26.172  INFO 1120 --- [nio-4000-exec-1] c.lqy.controller.SecondCacheController   : =====stuMapper1 student is com.lqy.entity.Student@1d636554
--------------------------------------------------------------------------------------------------------------------
Cache Hit Ratio [com.lqy.mapper.StudentMapper]: 0.0
==>  Preparing: select * from student where id = ?
==> Parameters: 1(Long)
<==    Columns: id, stu_no, stu_name, age, clazz_id, create_time, remark
<==        Row: 1, 1, 学生一, null, null, 2021-04-26 19:01:29.0, 1
<==      Total: 1
2021-06-23 16:03:26.175  INFO 1120 --- [nio-4000-exec-1] c.lqy.controller.SecondCacheController   : =====student2 student is com.lqy.entity.Student@3e8c7bc6
--------------------------------------------------------------------------------------------------------------------
Cache Hit Ratio [com.lqy.mapper.StudentMapper]: 0.3333333333333333
2021-06-23 16:03:26.177  INFO 1120 --- [nio-4000-exec-1] c.lqy.controller.SecondCacheController   : =====student3 student is com.lqy.entity.Student@4c304786


第二次请求:
Cache Hit Ratio [com.lqy.mapper.StudentMapper]: 0.5
2021-06-23 16:04:21.256  INFO 1120 --- [nio-4000-exec-2] c.lqy.controller.SecondCacheController   : =====stuMapper1 student is com.lqy.entity.Student@8dc27a9
--------------------------------------------------------------------------------------------------------------------
Cache Hit Ratio [com.lqy.mapper.StudentMapper]: 0.6
2021-06-23 16:04:21.256  INFO 1120 --- [nio-4000-exec-2] c.lqy.controller.SecondCacheController   : =====student2 student is com.lqy.entity.Student@61bc8c2
--------------------------------------------------------------------------------------------------------------------
Cache Hit Ratio [com.lqy.mapper.StudentMapper]: 0.6666666666666666
2021-06-23 16:04:21.257  INFO 1120 --- [nio-4000-exec-2] c.lqy.controller.SecondCacheController   : =====student3 student is com.lqy.entity.Student@2244cd9

 

 

6、查询使用flushCache、useCache清除缓存:@Options(flushCache = FlushCachePolicy.TRUE, useCache = false),二级缓存不生效

/**
 * flushCache:是否清除缓存,默认是DEFAULT
 *   FlushCachePolicy.DEFAULT:如果是查询(select)操作,则是false,其它更新(insert、update、delete)操作则是true
 *   
 * useCache:是否将查询数据放到二级缓存
 * @param id
 */
@Select("select * from student where id = #id")
@Options(flushCache = FlushCachePolicy.TRUE, useCache = false)
public Student get(Long id);

 

方法同二级缓存的:notSameSessionUpdate,现在缓存不生效

JDBC Connection [HikariProxyConnection@806642975 wrapping com.mysql.jdbc.JDBC4Connection@7c12637c] will not be managed by Spring
==>  Preparing: select * from student where id = ?
==> Parameters: 1(Long)
<==    Columns: id, stu_no, stu_name, age, clazz_id, create_time, remark
<==        Row: 1, 1, 学生一, null, null, 2021-04-26 19:01:29.0, 1
<==      Total: 1
2021-06-23 16:28:29.394  INFO 1120 --- [nio-4000-exec-4] c.lqy.controller.SecondCacheController   : =====stuMapper1 student is com.lqy.entity.Student@3aec0e6f
JDBC Connection [HikariProxyConnection@2146338646 wrapping com.mysql.jdbc.JDBC4Connection@7c12637c] will not be managed by Spring
==>  Preparing: update student set remark = ? where id = ?
==> Parameters: 1(Long), 1(Long)
<==    Updates: 1
JDBC Connection [HikariProxyConnection@337545723 wrapping com.mysql.jdbc.JDBC4Connection@7c12637c] will not be managed by Spring
==>  Preparing: select * from student where id = ?
==> Parameters: 1(Long)
<==    Columns: id, stu_no, stu_name, age, clazz_id, create_time, remark
<==        Row: 1, 1, 学生一, null, null, 2021-04-26 19:01:29.0, 1
<==      Total: 1
2021-06-23 16:28:29.439  INFO 1120 --- [nio-4000-exec-4] c.lqy.controller.SecondCacheController   : =====stuMapper2 student is com.lqy.entity.Student@7a2c82a9

 

7、二级缓存结论:
当执行一条查询sql时,先从二级缓存进行查询,没有则进入一级缓存查询,再没有就执行sql进行数据库查询,在会话(sqlSession)结束前把缓存放到一级缓存,会话结束后放到二级缓存中(需要开启二级缓存)。

手动清除查询的二级缓存

@Options(flushCache = FlushCachePolicy.TRUE, useCache = false)
flushCache:是否清除缓存,默认是DEFAULT,可以直接设置FlushCachePolicy.TRUE
    FlushCachePolicy.DEFAULT:如果是查询(select)操作,则是false,其它更新(insert、update、delete)操作则是true
useCache:是否将查询结果放到二级缓存

 

 

 

四、Mybatis整合EhCache

1、pom.xml文件引入mybatis-ehcache依赖

<!-- 使用:http://mybatis.org/ehcache-cache/ -->
<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.2.1</version>
</dependency>

 

2、Mapper类的缓存实现类改成:EhcacheCache.class

@CacheNamespace(implementation = EhcacheCache.class)
public interface StudentMapper 

 

3、增加ehcache.xml配置文件,放在classpath路径下(src/main/resources/ehcache.xml)

ehcache.xml内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="ehcache.xsd"
         updateCheck="true" monitoring="autodetect"
         dynamicConfig="true">

    <!-- ehcache 文件存放路径 -->
    <diskStore path="C:\\mybatis-cache"/>

    <!--defaultCache:默认的管理策略-->
    <!--查看详情  

mybatis一级缓存,mybatis二级缓存,mybatis缓存失效(代码片段)

Mybatis一级缓存,Mybatis二级缓存,Mybatis缓存失效 ================================©Copyright蕃薯耀 2021-06-24https://www.cnblogs.com/fanshuyao/ 一、SpringBoot整合Mybatis1、pom.xml引入依赖(基于SpringBoot:2.3.12.REL 查看详情

mybatis一级缓存和二级缓存

MyBatis中的缓存一级缓存:  Mybatis一级缓存的作用域是同一个SqlSession,在同一个sqlSession中执行两次相同的SQL语句,第一次执行完毕后会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据不再从数据库中查询... 查看详情

mybatis的二级缓存

文章目录MyBatis的二级缓存MyBatis默认是开启一级缓存的开启MyBatis的二级缓存为什么要开启二级缓存在mybatis的配置文件中进行配置在对应的mapper映射文件中声明相关的DO对象需要实现序列化测试动态代理接口执行更新方法后会清空... 查看详情

mybatis-一级缓存与二级缓存

 1.1  什么是查询缓存mybatis提供查询缓存,用于减轻数据压力,提高数据库性能。mybaits提供一级缓存,和二级缓存。 一级缓存是SqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,在对象中有一个(内存区... 查看详情

mybatis缓存,包含一级缓存与二级缓存,包括ehcache二级缓存

...了提高性能。明白了这一点下面我们开始进入正题。二,mybatis缓存概要①、mybatis的缓存有两种,分别是一级缓存和二级缓存。两者都属于查询缓存,也就是只有执行查询操作的时候才起缓存作用,对于增删改操作无效。②、一... 查看详情

mybatis一级缓存与二级缓存的区别你知道吗(代码片段)

前言Java面试经常问到Mybatis一级缓存和二级缓存,今天就给大家重点详解Mybatis一级缓存和二级缓存原理与区别。Mybatis缓存缓存就是内存中的数据,常常来自对数据库查询结果的保存,使用缓存可以避免频繁与数据库... 查看详情

mybatis一级缓存与二级缓存的区别你知道吗(代码片段)

前言Java面试经常问到Mybatis一级缓存和二级缓存,今天就给大家重点详解Mybatis一级缓存和二级缓存原理与区别。Mybatis缓存缓存就是内存中的数据,常常来自对数据库查询结果的保存,使用缓存可以避免频繁与数据库... 查看详情

mybatis的一级二级缓存?

1)一级缓存:基于PerpetualCache的HashMap本地缓存,其存储作用域为Session,当Sessionflush或close之后,该Session中的所有Cache就将清空,默认打开一级缓存。2)二级缓存与一级缓存其机制相同,默认也是采用PerpetualCache,HashMap存储,不同... 查看详情

mybatis缓存

基本概念一级缓存与session绑定,只存在于session生命周期内,从数据库中查询到的值会保存到一级缓存中,当session关闭后,会保存到二级缓存中,一级缓存默认是开启的。二级缓存存在于sqlSessionFactory生命周期内,多个session共享... 查看详情

mybatis一级缓存和二级缓存

缓存详细介绍,结果集展示https://blog.csdn.net/u013036274/article/details/55815104 配置信息http://www.pianshen.com/article/16399265/ ************详细介绍*************https://my.oschina.net/zjllovecode/blog/18175 查看详情

mybatis学习--缓存(一级和二级缓存)

声明:学习摘要!MyBatis缓存  我们知道,频繁的数据库操作是非常耗费性能的(主要是因为对于DB而言,数据是持久化在磁盘中的,因此查询操作需要通过IO,IO操作速度相比内存操作速度慢了好几个量级),尤其是对于一些... 查看详情

mybatis的一级缓存和二级缓存

一级缓存是SqlSession级别的缓存,当使用了clearCache方法和,或者close方法的话,这个缓存失效,如果还有同样的查询,则还会发送一次查询SqlSessionsession=SqlSessionFactoryUtil.getSession();Empemp=session.selectOne("queryEmpByNo",7900);System.out... 查看详情

课时10:mybatis一级缓存二级缓存

...缓存  1.一级缓存    1.1 同一个SqlSession对象,mybatis默认就开启了一级缓存,下方为示意图    1.2 如果用同样的SqlSession对象查询相同的数据,则只会在第一次查询时向数据库发送SQL语句,并将查询的结果放入SqlSessio... 查看详情

mybatis缓存

MyBatis的缓存正如大多数持久化框架一样,MyBatis提供了一级缓存和二级缓存的支持。1.一级缓存 一级缓存是基于perpetualCache(MyBatis自带)的HashMap本地缓存,作用范围为session域内,当sessionflush或者close之后,该session中所有的cac... 查看详情

mybatis缓存的使用和源码分析

Mybatis缓存使用在Mybatis中缓存分为一级缓存和二级缓存,二级缓存又称为全局缓存,默认一级缓存和二级缓存都是开启的,只是二级缓存的使用需要配置才能生效,在Mybatis中一级缓存是SqlSession级别也就是会话级别的,而二级缓... 查看详情

mybatis的一级缓存和二级缓存(代码片段)

一级缓存一级缓存在mybatis中默认是开启的并且是session级别,它的作用域为一次sqlSession会话。mybatis默认是开启了一级缓存的。一级缓存的作用域有两种:session(默认)和statment,可通过设置local-cache-scope的值... 查看详情

mybatis缓存之二级缓存

二级缓存(全局缓存):基于namespace级别的缓存,一个namespace对应一个二级缓存。工作机制:一个会话,查询一条数据,这条数据会放在当前会话的一级缓存中;如果会话关闭,该会话对应的一级缓存就消失了;可以使用二级缓... 查看详情