springboot-mybatisplus-redis二级缓存
前言
mybatis可以自己帶有二級緩存的實現,這里加上redis是想把東西緩存到redis中,而不是mybaits自帶的map中。這也就構成了我們看到的springboot + mybatisplus +redis實現二級緩存的題目。
具體步驟如下:
首先加入需要的依賴
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId> </dependency> <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId> </dependency>第二步:在application.properties或者yml中配置redis屬性和設置開啟二級緩存(默認是關閉的)
spring.cache.type=redis spring.redis.host=192.168.9.82 spring.redis.jedis.pool.max-active=10 spring.redis.jedis.pool.max-idle=10 spring.redis.jedis.pool.max-wait=3000 spring.redis.jedis.pool.min-idle=20 spring.redis.port=6379 spring.redis.timeout=3000mybatis-plus.configuration.cache-enabled=true #開啟二級緩存第三步:編寫redis緩存的配置類,大體需要如下三個類,先截圖在上代碼
?ApplicationContextHolder.java類主要用于在另外另個類中可以通過context獲取spring容器中注入的redisTemplate來操作redis。代碼如下:
import org.springframework.context.ApplicationContext;//@Component public class ApplicationContextHolder {private static ApplicationContext applicationContext = null;public static void setApplicationContext(ApplicationContext applicationContext) {ApplicationContextHolder.applicationContext = applicationContext;}public static ApplicationContext getApplicationContext() {return applicationContext;}public static <T> T getBean(String name) {return (T)applicationContext.getBean(name);}public static <T> T getBean(Class clz) {return (T)applicationContext.getBean(clz);}}MybatisRedisCache.java類實現了Mybatis的Cache接口,這樣才能在執(zhí)行數據庫操作前調用緩存。代碼如下:
import org.apache.ibatis.cache.Cache; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ValueOperations;import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock;public class MybatisRedisCache implements Cache {private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();private final String id; // cache instance idprivate RedisTemplate redisTemplate;private static final long EXPIRE_TIME_IN_MINUTES = 30; // redis過期時間public MybatisRedisCache(String id) {if (id == null) {throw new IllegalArgumentException("Cache instances require an ID");}this.id = id;}@Overridepublic String getId() {return id;}/*** Put query result to redis** @param key* @param value*/@Override@SuppressWarnings("unchecked")public void putObject(Object key, Object value) {try {RedisTemplate redisTemplate = getRedisTemplate();ValueOperations opsForValue = redisTemplate.opsForValue();opsForValue.set(key, value, EXPIRE_TIME_IN_MINUTES, TimeUnit.MINUTES);}catch (Throwable t) {t.printStackTrace();}}/*** Get cached query result from redis** @param key* @return*/@Overridepublic Object getObject(Object key) {try {RedisTemplate redisTemplate = getRedisTemplate();ValueOperations opsForValue = redisTemplate.opsForValue();return opsForValue.get(key);}catch (Throwable t) {return null;}}/*** Remove cached query result from redis** @param key* @return*/@Override@SuppressWarnings("unchecked")public Object removeObject(Object key) {try {RedisTemplate redisTemplate = getRedisTemplate();redisTemplate.delete(key);}catch (Throwable t) {t.getMessage();}return null;}/*** Clears this cache instance*/@Overridepublic void clear() {RedisTemplate redisTemplate = getRedisTemplate();redisTemplate.execute((RedisCallback) connection -> {connection.flushDb();return null;});}/*** This method is not used** @return*/@Overridepublic int getSize() {return 0;}@Overridepublic ReadWriteLock getReadWriteLock() {return readWriteLock;}private RedisTemplate getRedisTemplate() {if (redisTemplate == null) {// 這里用到了ApplicationContextHolder.javaredisTemplate = ApplicationContextHolder.getBean("redisTemplate");}return redisTemplate;} } RedisCacheConfig.java類主要用來配置redis的一些屬性,里面這里主要配置了reids序列化。代碼如下: import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.interceptor.CacheErrorHandler; import org.springframework.cache.interceptor.CacheResolver; import org.springframework.cache.interceptor.SimpleCacheErrorHandler; import org.springframework.cache.interceptor.SimpleCacheResolver; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisStandaloneConfiguration; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; 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.StringRedisSerializer;import java.time.Duration; import java.util.HashMap; import java.util.Map;/*** ignit改redis緩存* @author lhb* @since 2022/11/24*/ @Configuration public class RedisCacheConfig extends CachingConfigurerSupport {@Value("${spring.redis.host}")private String redisHost;@Value("${spring.redis.port}")private int redisPort;@Beanpublic RedisTemplate<Object, Object> redisTemplate() {RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(redisConnectionFactory());GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();redisTemplate.setKeySerializer(genericJackson2JsonRedisSerializer);redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);return redisTemplate;}@Overridepublic CacheResolver cacheResolver() {return new SimpleCacheResolver(cacheManager());}@Overridepublic CacheErrorHandler errorHandler() {return new SimpleCacheErrorHandler();}@Overridepublic CacheManager cacheManager() {Map<String, RedisCacheConfiguration> cacheConfigurationMap = generateCacheConfigMap();RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().disableCachingNullValues().serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));return RedisCacheManager.builder(redisConnectionFactory()).cacheDefaults(redisCacheConfiguration).withInitialCacheConfigurations(cacheConfigurationMap).build();}public Map<String, RedisCacheConfiguration> generateCacheConfigMap() {Map<String, RedisCacheConfiguration> initialCacheConfiguration = new HashMap<>();initialCacheConfiguration.put("hourCache", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(1)));//1小時initialCacheConfiguration.put("minCache", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(1)));initialCacheConfiguration.put("dayCache", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofDays(1)));return initialCacheConfiguration;}public RedisConnectionFactory redisConnectionFactory() {RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();configuration.setHostName(redisHost);configuration.setPort(redisPort);configuration.setDatabase(0);LettuceConnectionFactory factory = new LettuceConnectionFactory(configuration);factory.afterPropertiesSet();return factory;}}第四步:在mapper.xml中添加cache標簽,來告訴mybtisplus這個mapper中的內容使用二級緩存,這個cache標簽放在mapper表中的什么位置都行
<mapper namespace="hisense.HiDevMng.code.hidevConfigManager.web.dao.DevBusRouterelViewDao"><!-- 開啟基于redis的二級緩存 --><cache type="hisense.HiDevMng.code.base.config.cache.MybatisRedisCache"/><select id="getOrgList" resultType="his.api.dto.OrgDto">SELECT * from table1 WHERE br.BUSID IN<foreach collection="ids" index="index" item="item" open="(" separator="," close=")">#{item}</foreach></select> </mapper>第五步:在啟動類中實現ApplicationContextAware接口,目的是拿到spring容器的context,然后給ApplicationContextHolder,這樣我們的redis緩存的配置類中就可以通過applicationContext來得到容器中中的redisTemplate進行redis操作了。添加如下代碼:
public class StartApplication extends SpringBootServletInitializer implements ApplicationContextAware {public static void main(String[] args) {SpringApplication.run(StartApplication.class, args);}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {//重點在此,通過這個賦值contextApplicationContextHolder.setApplicationContext(applicationContext);} }網上很多帖子給出的方式是自己單獨寫一個類來實現ApplicationContextAware接口,但是因為我的項目中用到了@PostConstruct注解,那樣會導致ApplicationContrext為空,所以我選擇了通過上面在啟動類給ApplicationContextHolder賦值的方式。
第六步,測試,創(chuàng)建測試類例如
RunWith(SpringRunner.class) @SpringBootTest(classes = StartApplication.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) public class test {@Autowiredprivate MyDao dao;@Testpublic void testOne() {Set<String> ids = new HashSet<>();ids.add("25191027172915794000");List<BusOrgDto> busOrgList = dao.getBusOrgList(ids);System.out.println(busOrgList.size());System.out.println("====================================================");List<BusOrgDto> busOrgList1 = dao.getBusOrgList(ids);System.out.println(busOrgList1.size());}}?運行2次查詢,但是只出現一次如下圖的log,就說明第二次執(zhí)行使用redis緩存中的數據了
?出現一次Preparing:就說明執(zhí)行的是數據庫查詢,沒走redis緩存。當我們多次執(zhí)行都不在顯示這個Preparing:了就說明緩存成功了。
總結:
這里就不把代碼放git上了,直接從上面把代碼都拷貝下來,就可以執(zhí)行了。關于什么是二級緩存網上可以自行百度。
代碼中還存在完善的空間,比如多久后自動從緩存刪除等,大家可以自行了解下。這里只是為了給初學者使用,寫多了怕容易亂。謝謝支持
總結
以上是生活随笔為你收集整理的springboot-mybatisplus-redis二级缓存的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Redis的LRU缓存淘汰算法实现
- 下一篇: 如何安装VMTools以及安装VMToo