Mybatis 一级缓存,Mybatis 二级缓存,Mybatis 缓存失效
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:默认的管理策略--> <!--eternal:设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断--> <!--maxElementsInMemory:在内存中缓存的element的最大数目--> <!--overflowToDisk:如果内存中数据超过内存限制,是否要缓存到磁盘上--> <!--diskPersistent:是否在磁盘上持久化。指重启jvm后,数据是否有效。默认为false--> <!--timeToIdleSeconds:对象空闲时间(单位:秒),指对象在多长时间没有被访问就会失效。只对eternal为false的有效。默认值0,表示一直可以访问--> <!--timeToLiveSeconds:对象存活时间(单位:秒),指对象从创建到失效所需要的时间。只对eternal为false的有效。默认值0,表示一直可以访问--> <!--memoryStoreEvictionPolicy:缓存的3 种清空策略--> <!--FIFO:first in first out (先进先出)--> <!--LFU:Less Frequently Used (最少使用).意思是一直以来最少被使用的。缓存的元素有一个hit 属性,hit 值最小的将会被清出缓存--> <!--LRU:Least Recently Used(最近最少使用). (ehcache 默认值).缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存--> <defaultCache maxEntriesLocalHeap="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk=true diskPersistent=true diskSpoolBufferSizeMB="30" maxEntriesLocalDisk="10000000" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> <persistence strategy="localTempSwap"/> </defaultCache> </ehcache>
4、启动项目测试
路径C:\mybatis-cache下会多出ehcache的文件,二级缓存同时生效。
Cache Hit Ratio [com.lqy.mapper.StudentMapper]: 0.5
Cache Hit Ratio [com.lqy.mapper.StudentMapper]: 0.6666666666666666
(时间宝贵,分享不易,捐赠回馈,^_^)
================================
©Copyright 蕃薯耀 2021-06-24
https://www.cnblogs.com/fanshuyao/