0


Spring Boot 集成 Redis 配置 MyBatis 二级缓存

目录

写在前面

文中项目基于从0到1项目搭建-框架搭建,如果你是新手,可以跟着上期内容先动手把项目框架搭建起来,然后在结合本期内容继续深入学习,这样会有更好的效果。

接下来正式介绍本文,本文讲的是在 Spring Boot 项目中集成使用 Redis,并使用 Redis 实现 MyBatis 的二级缓存。使用场景就是在高并发的环境下,大量的查询直接落入DB,会导致数据库宕机,从而导致服务雪崩的情况。我们使用Redis作为MyBatis二级缓存,可以充分的缓解数据库的压力,从而达到服务的高可用。

源码获取

源码在

GitCode

GitHub

以及

码云

,持续更新中,别忘了

star

喔~

GitCode

https://gitcode.net/qq_41779565/my-project.git

GitHub

https://github.com/micromaples/my-project

码云Gitee

https://gitee.com/micromaple/my-project

如果不会使用 Git 的小伙伴,我已经上传到了CSDN,资源下载传送门,有会员的小伙伴直接下载即可,没有会员的小伙伴私聊我

Mybatis二级缓存

可直接获取

一、MyBatis缓存机制

Mybatis 提供了查询缓存来缓存数据,以提高查询效率。缓存级别分为

一级缓存

二级缓存

1.1、一级缓存

一级缓存为

SqlSession

级别的缓存,也就是会话级缓存,是基于

HashMap

的本地缓存,当同一个

SqlSession

执行两次相同的

SQL

语句时,第一次执行完后会将数据库中查询到的结果写到缓存,第二次查询时直接从缓存中读取,不经过数据库了。一级缓存默认是开启的。

1.2、二级缓存

二级缓存为mapper级别的缓存,多个

SqlSession

去操作同一个 Mapper 的 sql 语句,多个 SqlSession 去操作数据库得到数据会存在二级缓存区域,多个 SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。其作用域是 mapper 的同一个

namespace

,不同的 sqlSession 两次执行相同 namespace下的 sql 语句且向 sql 中传递参数也相同即最终执行相同的 sql 语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。Mybatis 默认没有开启二级缓存需要在 setting 全局参数中配置开启二级缓存。

二、集成Redis

2.1、安装Redis

使用

Docker Compose

安装Redis。

docker-compose.yml

内容如下:

version:'3.1'services:redis:image: redis:6.2.4
    container_name: redis
    restart: always
    command: redis-server --requirepass 123456
    ports:-'6379:6379'volumes:- ./data:/data
    environment:TZ: Asia/Shanghai

安装启动完成后,可使用Redis连接工具测试

在这里插入图片描述

2.2、项目引入Redis

2.2.1、Maven依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency>

额外引入commons-pool2是因为data-redis底层Redis连接池基于apache commons-pool2开 发,不加入依赖会报

ClassNotFoundException

2.2.2、配置application.yml

spring:redis:host: 192.168.110.158
    port:6379password:123456lettuce:pool:#最大允许连接数max-active:100#最小空闲连接数,最少准备5个可用连接在连接池候着min-idle:5#最大空闲连接数,空闲连接超过10个后自动释放max-idle:10#当连接池到达上限后,最多等待30秒尝试获取连接,超时报错max-wait:30000timeout:2000

2.2.3、配置序列化规则

RedisTemplateConfiguration

配置类如下:

packagecom.micromaple.my.project.server.config;importcom.fasterxml.jackson.annotation.JsonInclude;importcom.fasterxml.jackson.databind.ObjectMapper;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.data.redis.connection.RedisConnectionFactory;importorg.springframework.data.redis.core.RedisTemplate;importorg.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;importorg.springframework.data.redis.serializer.StringRedisSerializer;/**
 * RedisTemplate配置
 * Title: RedisTemplateConfiguration
 * Description:
 *
 * @author Micromaple
 */@ConfigurationpublicclassRedisTemplateConfiguration{/**
     * redisTemplate
     *
     * @param redisConnectionFactory
     * @return
     */@BeanpublicRedisTemplate<Object,Object>redisTemplate(RedisConnectionFactory
                                                               redisConnectionFactory){RedisTemplate<Object,Object> redisTemplate =newRedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);// 使用Jackson2JsonRedisSerialize 替换默认序列化Jackson2JsonRedisSerializer jackson2JsonRedisSerializer =newJackson2JsonRedisSerializer(Object.class);ObjectMapper objectMapper =newObjectMapper();//对于Null值不输出
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);// 设置key和value的序列化规则
        redisTemplate.setKeySerializer(newStringRedisSerializer());
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);// 设置hashKey和hashValue的序列化规则
        redisTemplate.setHashKeySerializer(newStringRedisSerializer());
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);//afterPropertiesSet和init-method之间的执行顺序是afterPropertiesSet 先执行,init - method 后执行。
        redisTemplate.afterPropertiesSet();return redisTemplate;}}

三、配置二级缓存

配置实现MyBatis二级缓存的方式有多种,比如:

EhCache

JBossCache

Redis

,其核心原理就是客户端实现 MyBatis 提供的

Cache

接口,并重写其中的方法,达到二级缓存的效果。

本文以 Redis 为例。

2.1、开启二级缓存

application.yml

中增加如下配置:

# 开启MyBatis二级缓存mybatis:configuration:cache-enabled:true

如果使用的是

MyBatis-Plus

,则使用如下配置:

# MyBatis-Plus开启二级缓存mybatis-plus:configuration:cache-enabled:true

2.2、自定义缓存类

MybatisRedisCache

缓存工具类如下:

packagecom.micromaple.my.project.server.utils;importcom.micromaple.my.project.server.config.ApplicationContextHolder;importorg.apache.commons.collections.CollectionUtils;importorg.apache.ibatis.cache.Cache;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.data.redis.core.RedisTemplate;importjava.util.Set;importjava.util.concurrent.TimeUnit;importjava.util.concurrent.locks.ReadWriteLock;importjava.util.concurrent.locks.ReentrantReadWriteLock;/**
 * MybatisRedisCache 缓存工具类
 * Title: MybatisRedisCache
 * Description:
 *
 * @author Micromaple
 */publicclassMybatisRedisCacheimplementsCache{privatestaticfinalLogger logger =LoggerFactory.getLogger(MybatisRedisCache.class);privatefinalReadWriteLock readWriteLock =newReentrantReadWriteLock();privatefinalString id;// cache instance idprivateRedisTemplate redisTemplate;privatestaticfinallong EXPIRE_TIME_IN_MINUTES =30;// redis过期时间publicMybatisRedisCache(String id){if(id ==null){thrownewIllegalArgumentException("Cache instances require an ID");}this.id = id;}@OverridepublicStringgetId(){return id;}/**
     * Put query result to redis
     *
     * @param key
     * @param value
     */@OverridepublicvoidputObject(Object key,Object value){try{
            redisTemplate =getRedisTemplate();if(value !=null){
                redisTemplate.opsForValue().set(key.toString(), value, EXPIRE_TIME_IN_MINUTES,TimeUnit.MINUTES);}
            logger.debug("Put query result to redis");}catch(Throwable t){
            logger.error("Redis put failed", t);}}/**
     * Get cached query result from redis
     *
     * @param key
     * @return
     */@OverridepublicObjectgetObject(Object key){try{
            redisTemplate =getRedisTemplate();
            logger.debug("Get cached query result from redis");return redisTemplate.opsForValue().get(key.toString());}catch(Throwable t){
            logger.error("Redis get failed, fail over to db", t);returnnull;}}/**
     * Remove cached query result from redis
     *
     * @param key
     * @return
     */@Override@SuppressWarnings("unchecked")publicObjectremoveObject(Object key){try{
            redisTemplate =getRedisTemplate();
            redisTemplate.delete(key.toString());
            logger.debug("Remove cached query result from redis");}catch(Throwable t){
            logger.error("Redis remove failed", t);}returnnull;}/**
     * Clears this cache instance
     */@Overridepublicvoidclear(){
        redisTemplate =getRedisTemplate();Set<String> keys = redisTemplate.keys("*:"+this.id +"*");if(!CollectionUtils.isEmpty(keys)){
            redisTemplate.delete(keys);}
        logger.debug("Clear all the cached query result from redis");}/**
     * This method is not used
     *
     * @return
     */@OverridepublicintgetSize(){return0;}@OverridepublicReadWriteLockgetReadWriteLock(){return readWriteLock;}privateRedisTemplategetRedisTemplate(){if(redisTemplate ==null){
            redisTemplate =ApplicationContextHolder.getBean("redisTemplate");}return redisTemplate;}}
ApplicationContextHolder

如下:

packagecom.micromaple.my.project.server.config;importorg.apache.commons.lang3.Validate;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.beans.BeansException;importorg.springframework.beans.factory.DisposableBean;importorg.springframework.context.ApplicationContext;importorg.springframework.context.ApplicationContextAware;importorg.springframework.stereotype.Component;/**
 * Spring bean的工具类
 * Title: ApplicationContextHolder
 * Description:
 *
 * @author Micromaple
 */@ComponentpublicclassApplicationContextHolderimplementsApplicationContextAware,DisposableBean{privatestaticfinalLogger logger =LoggerFactory.getLogger(ApplicationContextHolder.class);privatestaticApplicationContext applicationContext;/**
     * 获取存储在静态变量中的 ApplicationContext
     *
     * @return
     */publicstaticApplicationContextgetApplicationContext(){assertContextInjected();return applicationContext;}/**
     * 从静态变量 applicationContext 中获取 Bean,自动转型成所赋值对象的类型
     *
     * @param name
     * @param <T>
     * @return
     */publicstatic<T>TgetBean(String name){assertContextInjected();return(T) applicationContext.getBean(name);}/**
     * 从静态变量 applicationContext 中获取 Bean,自动转型成所赋值对象的类型
     *
     * @param clazz
     * @param <T>
     * @return
     */publicstatic<T>TgetBean(Class<T> clazz){assertContextInjected();return applicationContext.getBean(clazz);}/**
     * 实现 DisposableBean 接口,在 Context 关闭时清理静态变量
     *
     * @throws Exception
     */publicvoiddestroy()throwsException{
        logger.debug("清除 SpringContext 中的 ApplicationContext: {}", applicationContext);
        applicationContext =null;}/**
     * 实现 ApplicationContextAware 接口,注入 Context 到静态变量中
     *
     * @param applicationContext
     * @throws BeansException
     */publicvoidsetApplicationContext(ApplicationContext applicationContext)throwsBeansException{ApplicationContextHolder.applicationContext = applicationContext;}/**
     * 断言 Context 已经注入
     */privatestaticvoidassertContextInjected(){Validate.validState(applicationContext !=null,"applicationContext 属性未注入,请在 spring-context.xml 配置中定义 SpringContext");}}

2.3、增加注解

在 Mapper 接口中增加

@CacheNamespace(implementation = MybatisRedisCache.class)

注解,声明需要使用二级缓存。

packagecom.micromaple.my.project.server.mapper;importcom.baomidou.mybatisplus.core.mapper.BaseMapper;importcom.micromaple.my.project.server.domain.SysUser;importcom.micromaple.my.project.server.utils.MybatisRedisCache;importorg.apache.ibatis.annotations.CacheNamespace;/**
 * <p>
 * 用户表 Mapper 接口
 * </p>
 *
 * @author Micromaple
 * @since 2022-09-21 21:51:15
 */@CacheNamespace(implementation =MybatisRedisCache.class)publicinterfaceSysUserMapperextendsBaseMapper<SysUser>{}

2.4、测试验证

访问查询所有用户接口

http://localhost:8899/sys-user/get/all

访问完成后,我们打开Redis查询工具,可以看到已经将我们查询出来的数据缓存起来了。效果图如下:
在这里插入图片描述

接着,我们再次访问查询所有用户接口,我们可以在控制台日志中看到,第二次查询并没有走数据库,而是直接在Redis中取出来了

在这里插入图片描述


本文转载自: https://blog.csdn.net/qq_41779565/article/details/127133675
版权归原作者 微枫Micromaple 所有, 如有侵权,请联系我们删除。

“Spring Boot 集成 Redis 配置 MyBatis 二级缓存”的评论:

还没有评论