【数据篇】SpringBoot 整合 MyBatis 组合 Redis 作为数据源缓存 |
您所在的位置:网站首页 › mybatis操作redis › 【数据篇】SpringBoot 整合 MyBatis 组合 Redis 作为数据源缓存 |
写在最前
MyBatis 是常见的 Java 数据库访问层框架。在日常工作中,开发人员多数情况下是使用 MyBatis 的默认缓存配置,但是 MyBatis 缓存机制有一些不足之处,在使用中容易引起脏数据,形成一些潜在的隐患。 本文介绍的是 Redis 组合 MyBatis 作为数据源缓存。**并不是用 Redis 作为 Mybatis 的二级缓存类型!,也不是使用 Mybatis 一级缓存或二级缓存作为数据源缓存 **。 本文不再重复介绍 SpringBoot 如何整合 MyBatis。想学习 SpringBoot 整合 MyBatis 的同学可以参考下面文章,希望对您有所帮助: 【数据篇】SpringBoot 整合 MyBatis 操作 MySql MyBatis 一级缓存与二级缓存虽然本文不是使用 Mybatis 一级缓存或二级缓存作为数据源缓存,但还是要简单介绍一下 MyBatis 一级缓存与二级缓存,以及为什么不使用其一级缓存或二级缓存,而是推荐使用 Redis 组合 Mybatis 的可控制的缓存代替二级缓存! 推荐阅读文章:tech.meituan.com/2018/01/19/… 一级缓存在应用运行过程中,我们有可能在一次数据库会话中,执行多次查询条件完全相同的SQL,MyBatis 提供了一级缓存的方案优化这部分场景,如果是相同的 SQL 语句,会优先命中一级缓存,避免直接对数据库进行查询,提高性能。具体执行过程如下图所示。 一级缓存小结: MyBatis 一级缓存的生命周期和 SqlSession 一致。 MyBatis 一级缓存内部设计简单,只是一个没有容量限定的 HashMap,在缓存的功能性上有所欠缺。 MyBatis 的一级缓存最大范围是 SqlSession 内部,有多个 SqlSession 或者分布式的环境下,数据库写操作会引起脏数据,建议设定缓存级别为 Statement。 二级缓存在上文中提到的一级缓存中,其最大的共享范围就是一个 SqlSession 内部,如果多个 SqlSession 之间需要共享缓存,则需要使用到二级缓存。开启二级缓存后,会使用 CachingExecutor 装饰 Executor,进入一级缓存的查询流程前,先在CachingExecutor 进行二级缓存的查询,具体的工作流程如下所示。 二级缓存开启后,同一个 namespace 下的所有操作语句,都影响着同一个 Cache,即二级缓存被多个 SqlSession 共享,是一个全局的变量。 当开启缓存后,数据的查询执行的流程就是 二级缓存 -> 一级缓存 -> 数据库。 二级缓存小结: MyBatis 的二级缓存相对于一级缓存来说,实现了SqlSession之间缓存数据的共享,同时粒度更加的细,能够到namespace级别,通过 Cache 接口实现类不同的组合,对 Cache 的可控性也更强。 MyBatis 在多表查询时,极大可能会出现脏数据,有设计上的缺陷,安全使用二级缓存的条件比较苛刻。 在分布式环境下,由于默认的 MyBatis Cache 实现都是基于本地的,分布式环境下必然会出现读取到脏数据,需要使用集中式缓存将 MyBatis 的 Cache 接口实现,有一定的开发成本,直接使用 Redis、Memcached 等分布式缓存可能成本更低,安全性也更高。 SpringBoot MyBatis 整合 Redis Cache本工程基于 mingyue-springboot-mybatis 改造 1. 增加 Redis 依赖 org.springframework.boot spring-boot-starter-data-redis 2. 增加 Redis 修改配置 spring: redis: host: 127.0.0.1 password: 123456 port: 6379 3. 添加 Redis 配置类 import org.springframework.cache.CacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.cache.RedisCacheWriter; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializationContext; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; import java.time.Duration; /** * Redis 配置 * * @author Strive * @date 2023/4/18 18:53 */ @Configuration public class RedisConfig { @Bean(name = "redisTemplate") public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){ RedisTemplate redisTemplate = new RedisTemplate(); redisTemplate.setConnectionFactory(redisConnectionFactory); redisTemplate.setKeySerializer(keySerializer()); redisTemplate.setHashKeySerializer(keySerializer()); redisTemplate.setValueSerializer(valueSerializer()); redisTemplate.setHashValueSerializer(valueSerializer()); return redisTemplate; } @Primary @Bean public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory){ //缓存配置对象 RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig(); redisCacheConfiguration = redisCacheConfiguration //设置缓存的默认超时时间:30分钟 .entryTtl(Duration.ofMinutes(30L)) //如果是空值,不缓存 .disableCachingNullValues() //设置key序列化器 .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer())) //设置value序列化器 .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer((valueSerializer()))); return RedisCacheManager .builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory)) .cacheDefaults(redisCacheConfiguration).build(); } private RedisSerializer keySerializer() { return new StringRedisSerializer(); } private RedisSerializer valueSerializer() { return new GenericJackson2JsonRedisSerializer(); } } 4. 改造 queryUserById 方法 /** * 根据用户ID查询用户信息 * * @param userId 用户ID * @return 用户信息 */ @Cacheable(cacheNames = "userInfo",key = "#userId") public MingYueUser queryUserById(Long userId) { return sysUserMapper.queryUserById(userId); } 5. 开启 @EnableCaching 注解 @SpringBootApplication @EnableCaching public class MingYueSpringbootMybatisRedisCacheApplication { public static void main(String[] args) { SpringApplication.run(MingYueSpringbootMybatisRedisCacheApplication.class, args); } } 6. 启动项目,测试接口1.调用接口 http://127.0.0.1:8080/user/1,可以看到控制台有如下打印: JDBC Connection [HikariProxyConnection@1552674017 wrapping com.mysql.cj.jdbc.ConnectionImpl@315ae5d4] will not be managed by Spring ==> Preparing: select * from sys_user where user_id = ? ==> Parameters: 1(Long) Parameters: Strive Update 2023 33(String), 2(Long) Preparing: delete from sys_user where user_id = ? ==> Parameters: 2(Long) |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |