0


MyBatis Plus整合Redis实现分布式二级缓存

MyBatis缓存描述

MyBatis提供了两种级别的缓存, 分别时一级缓存和二级缓存。一级缓存是SqlSession级别的缓存,只在SqlSession对象内部存储缓存数据,如果SqlSession对象不一样就无法命中缓存,二级缓存是mapper级别的缓存,只要使用的Mapper类一样就能够共享缓存。

在查询数据时,Mybatis会优先查询二级缓存,如果二级缓存没有则查询一级缓存,都没有才会进行数据库查询。

Mybatis的一级缓存默认是开启的,而二级缓存需要在mapper.xml配置文件内或通过@CacheNamespace注解手动开启。

需要注意的是,在于Spring进行整合时,必须开启事务一级缓存会生效,因为不开启缓存的话每次查询都会重新创建一个SqlSession对象,因此无法共享缓存。

通过@CacheNamespace开启某个Mapper的二级缓存。

@Mapper@CacheNamespacepublicinterfaceEmployeeMapperextendsBaseMapper<Employee>{}

开启所有的二级缓存:

mybatis-plus:mapper-locations: classpath:mybatis/mapper/*.xmlconfiguration:cache-enabled:true

MybatisPlus整合Redis实现分布式二级缓存

Mybatis内置的二级缓存在分布式环境下存在分布式问题,无法使用,但是我们可以整合Redis来实现分布式的二级缓存。

1.引入依赖

<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.4.1</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.24.3</version></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.22</version></dependency>

2.配置RedisTemplate

importcom.fasterxml.jackson.annotation.JsonAutoDetect;importcom.fasterxml.jackson.annotation.PropertyAccessor;importcom.fasterxml.jackson.databind.ObjectMapper;importcom.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;importorg.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;importorg.springframework.cache.CacheManager;importorg.springframework.cache.annotation.EnableCaching;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.context.annotation.Primary;importorg.springframework.data.redis.cache.RedisCacheConfiguration;importorg.springframework.data.redis.cache.RedisCacheManager;importorg.springframework.data.redis.cache.RedisCacheWriter;importorg.springframework.data.redis.connection.RedisConnectionFactory;importorg.springframework.data.redis.core.RedisTemplate;importorg.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;importorg.springframework.data.redis.serializer.RedisSerializationContext;importorg.springframework.data.redis.serializer.RedisSerializer;importorg.springframework.data.redis.serializer.StringRedisSerializer;importjava.time.Duration;@Configuration@EnableCachingpublicclassRedisConfiguration{privatestaticfinalStringRedisSerializerSTRING_SERIALIZER=newStringRedisSerializer();privatestaticfinalGenericJackson2JsonRedisSerializerJACKSON__SERIALIZER=newGenericJackson2JsonRedisSerializer();@Bean@PrimarypublicCacheManagerredisCacheManager(RedisConnectionFactory redisConnectionFactory){//设置缓存过期时间RedisCacheConfiguration redisCacheCfg =RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(1)).serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(STRING_SERIALIZER)).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(JACKSON__SERIALIZER));returnRedisCacheManager.builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory)).cacheDefaults(redisCacheCfg).build();}@Bean@Primary@ConditionalOnMissingBean(name ="redisTemplate")publicRedisTemplate<String,Object>redisTemplate(RedisConnectionFactory factory){// 配置redisTemplateRedisTemplate<String,Object> redisTemplate =newRedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);// key序列化
        redisTemplate.setKeySerializer(STRING_SERIALIZER);// value序列化
        redisTemplate.setValueSerializer(JACKSON__SERIALIZER);// Hash key序列化
        redisTemplate.setHashKeySerializer(STRING_SERIALIZER);// Hash value序列化
        redisTemplate.setHashValueSerializer(JACKSON__SERIALIZER);// 设置支持事务
        redisTemplate.setEnableTransactionSupport(true);

        redisTemplate.afterPropertiesSet();return redisTemplate;}@BeanpublicRedisSerializer<Object>redisSerializer(){//创建JSON序列化器ObjectMapper objectMapper =newObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL,JsonAutoDetect.Visibility.ANY);//必须设置,否则无法将JSON转化为对象,会转化成Map类型
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL);returnnewGenericJackson2JsonRedisSerializer(objectMapper);}}

3.自定义缓存类

importcn.hutool.extra.spring.SpringUtil;importcn.hutool.json.JSONUtil;importlombok.extern.slf4j.Slf4j;importorg.apache.ibatis.cache.Cache;importorg.redisson.api.RReadWriteLock;importorg.redisson.api.RedissonClient;importorg.springframework.data.redis.connection.RedisServerCommands;importorg.springframework.data.redis.core.RedisCallback;importorg.springframework.data.redis.core.RedisTemplate;importjava.util.Set;importjava.util.concurrent.TimeUnit;importjava.util.concurrent.locks.ReadWriteLock;@Slf4jpublicclassMybatisRedisCacheimplementsCache{// redisson 读写锁privatefinalRReadWriteLock redissonReadWriteLock;// redisTemplateprivatefinalRedisTemplate redisTemplate;// 缓存IdprivatefinalString id;//过期时间 10分钟privatefinallong expirationTime =1000*60*10;publicMybatisRedisCache(String id){this.id = id;//获取redisTemplatethis.redisTemplate =SpringUtil.getBean(RedisTemplate.class);//创建读写锁this.redissonReadWriteLock =SpringUtil.getBean(RedissonClient.class).getReadWriteLock("mybatis-cache-lock:"+this.id);}@OverridepublicvoidputObject(Object key,Object value){//使用redis的Hash类型进行存储
        redisTemplate.opsForValue().set(getCacheKey(key),value,expirationTime,TimeUnit.MILLISECONDS);}@OverridepublicObjectgetObject(Object key){try{//根据key从redis中获取数据Object cacheData = redisTemplate.opsForValue().get(getCacheKey(key));

            log.debug("[Mybatis 二级缓存]查询缓存,cacheKey={},data={}",getCacheKey(key),JSONUtil.toJsonStr(cacheData));return cacheData;}catch(Exception e){
            log.error("缓存出错",e);}returnnull;}@OverridepublicObjectremoveObject(Object key){if(key !=null){
            log.debug("[Mybatis 二级缓存]删除缓存,cacheKey={}",getCacheKey(key));
            redisTemplate.delete(key.toString());}returnnull;}@Overridepublicvoidclear(){
        log.debug("[Mybatis 二级缓存]清空缓存,id={}",getCachePrefix());Set keys = redisTemplate.keys(getCachePrefix()+":*");
        redisTemplate.delete(keys);}@OverridepublicintgetSize(){Long size =(Long) redisTemplate.execute((RedisCallback<Long>)RedisServerCommands::dbSize);return size.intValue();}@OverridepublicReadWriteLockgetReadWriteLock(){returnthis.redissonReadWriteLock;}@OverridepublicStringgetId(){returnthis.id;}publicStringgetCachePrefix(){return"mybatis-cache:%s".formatted(this.id);}privateStringgetCacheKey(Object key){returngetCachePrefix()+":"+key;}}

4.Mapper接口上开启二级缓存

//开启二级缓存并指定缓存类@CacheNamespace(implementation =MybatisRedisCache.class,eviction =MybatisRedisCache.class)@MapperpublicinterfaceEmployeeMapperextendsBaseMapper<Employee>{}
标签: mybatis redis 分布式

本文转载自: https://blog.csdn.net/dndndnnffj/article/details/134366561
版权归原作者 爱码猿 所有, 如有侵权,请联系我们删除。

“MyBatis Plus整合Redis实现分布式二级缓存”的评论:

还没有评论