MyBatis Plus整合Redis實(shí)現(xiàn)分布式二級緩存的問題
MyBatis緩存描述
MyBatis提供了兩種級別的緩存, 分別時(shí)一級緩存和二級緩存。一級緩存是SqlSession級別的緩存,只在SqlSession對象內(nèi)部存儲緩存數(shù)據(jù),如果SqlSession對象不一樣就無法命中緩存,二級緩存是mapper級別的緩存,只要使用的Mapper類一樣就能夠共享緩存。
在查詢數(shù)據(jù)時(shí),Mybatis會優(yōu)先查詢二級緩存,如果二級緩存沒有則查詢一級緩存,都沒有才會進(jìn)行數(shù)據(jù)庫查詢。
Mybatis的一級緩存默認(rèn)是開啟的,而二級緩存需要在mapper.xml配置文件內(nèi)或通過@CacheNamespace注解手動開啟。
需要注意的是,在于Spring進(jìn)行整合時(shí),必須開啟事務(wù)一級緩存會生效,因?yàn)椴婚_啟緩存的話每次查詢都會重新創(chuàng)建一個SqlSession對象,因此無法共享緩存。
通過@CacheNamespace開啟某個Mapper的二級緩存。
@Mapper @CacheNamespace public interface EmployeeMapper extends BaseMapper<Employee> { }
開啟所有的二級緩存:
mybatis-plus: mapper-locations: classpath:mybatis/mapper/*.xml configuration: cache-enabled: true
MybatisPlus整合Redis實(shí)現(xiàn)分布式二級緩存
Mybatis內(nèi)置的二級緩存在分布式環(huán)境下存在分布式問題,無法使用,但是我們可以整合Redis來實(shí)現(xiàn)分布式的二級緩存。
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
import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.EnableCaching; 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; @Configuration @EnableCaching public class RedisConfiguration { private static final StringRedisSerializer STRING_SERIALIZER = new StringRedisSerializer(); private static final GenericJackson2JsonRedisSerializer JACKSON__SERIALIZER = new GenericJackson2JsonRedisSerializer(); @Bean @Primary public CacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) { //設(shè)置緩存過期時(shí)間 RedisCacheConfiguration redisCacheCfg = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofHours(1)) .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(STRING_SERIALIZER)) .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(JACKSON__SERIALIZER)); return RedisCacheManager.builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory)) .cacheDefaults(redisCacheCfg) .build(); } @Bean @Primary @ConditionalOnMissingBean(name = "redisTemplate") public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { // 配置redisTemplate RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); 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); // 設(shè)置支持事務(wù) redisTemplate.setEnableTransactionSupport(true); redisTemplate.afterPropertiesSet(); return redisTemplate; } @Bean public RedisSerializer<Object> redisSerializer() { //創(chuàng)建JSON序列化器 ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); //必須設(shè)置,否則無法將JSON轉(zhuǎn)化為對象,會轉(zhuǎn)化成Map類型 objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL); return new GenericJackson2JsonRedisSerializer(objectMapper); } }
3.自定義緩存類
import cn.hutool.extra.spring.SpringUtil; import cn.hutool.json.JSONUtil; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.cache.Cache; import org.redisson.api.RReadWriteLock; import org.redisson.api.RedissonClient; import org.springframework.data.redis.connection.RedisServerCommands; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisTemplate; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReadWriteLock; @Slf4j public class MybatisRedisCache implements Cache { // redisson 讀寫鎖 private final RReadWriteLock redissonReadWriteLock; // redisTemplate private final RedisTemplate redisTemplate; // 緩存Id private final String id; //過期時(shí)間 10分鐘 private final long expirationTime = 1000*60*10; public MybatisRedisCache(String id) { this.id = id; //獲取redisTemplate this.redisTemplate = SpringUtil.getBean(RedisTemplate.class); //創(chuàng)建讀寫鎖 this.redissonReadWriteLock = SpringUtil.getBean(RedissonClient.class).getReadWriteLock("mybatis-cache-lock:"+this.id); } @Override public void putObject(Object key, Object value) { //使用redis的Hash類型進(jìn)行存儲 redisTemplate.opsForValue().set(getCacheKey(key),value,expirationTime, TimeUnit.MILLISECONDS); } @Override public Object getObject(Object key) { try { //根據(jù)key從redis中獲取數(shù)據(jù) 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); } return null; } @Override public Object removeObject(Object key) { if (key != null) { log.debug("[Mybatis 二級緩存]刪除緩存,cacheKey={}",getCacheKey(key)); redisTemplate.delete(key.toString()); } return null; } @Override public void clear() { log.debug("[Mybatis 二級緩存]清空緩存,id={}",getCachePrefix()); Set keys = redisTemplate.keys(getCachePrefix()+":*"); redisTemplate.delete(keys); } @Override public int getSize() { Long size = (Long) redisTemplate.execute((RedisCallback<Long>) RedisServerCommands::dbSize); return size.intValue(); } @Override public ReadWriteLock getReadWriteLock() { return this.redissonReadWriteLock; } @Override public String getId() { return this.id; } public String getCachePrefix(){ return "mybatis-cache:%s".formatted(this.id); } private String getCacheKey(Object key){ return getCachePrefix()+":"+key; } }
4.Mapper接口上開啟二級緩存
//開啟二級緩存并指定緩存類 @CacheNamespace(implementation = MybatisRedisCache.class,eviction = MybatisRedisCache.class) @Mapper public interface EmployeeMapper extends BaseMapper<Employee> { }
到此這篇關(guān)于MyBatis Plus整合Redis實(shí)現(xiàn)分布式二級緩存的文章就介紹到這了,更多相關(guān)MyBatis Plus整合Redis二級緩存內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Java后端優(yōu)雅驗(yàn)證參數(shù)合法性
這篇文章主要介紹了詳解Java后端優(yōu)雅驗(yàn)證參數(shù)合法性,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02Eclipse將Maven項(xiàng)目打成jar包的方法
這篇文章主要介紹了Eclipse將Maven項(xiàng)目打成jar包的方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2007-09-09Java事件處理機(jī)制(自定義事件)實(shí)例詳解
這篇文章主要介紹了Java事件處理機(jī)制(自定義事件)實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2016-12-12java實(shí)現(xiàn)圖像轉(zhuǎn)碼為字符畫的方法
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)圖像轉(zhuǎn)碼為字符畫的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03