SpringBoot集成Redis及Redis使用方法
應(yīng)用背景
將一些經(jīng)常展現(xiàn)和不會頻繁變更的數(shù)據(jù),存放在存取速率更快的地方。 緩存就是一個存儲器,在技術(shù)選型中,常用 Redis 作為緩存數(shù)據(jù)庫,可以幫我們分散掉數(shù)據(jù)庫的壓力,有了它能更好的支持并發(fā)性能,主要是在獲取資源方便性能優(yōu)化的關(guān)鍵方面??梢赃@樣理解redis位于數(shù)據(jù)庫和springboot框架之間,起到數(shù)據(jù)緩存的作用。
Redis簡介
- Redis介紹:Redis是現(xiàn)在最受歡迎的NoSQL數(shù)據(jù)庫之一,Redis是一個使用ANSI C編寫的開源、包含多種數(shù)據(jù)結(jié)構(gòu)、支持網(wǎng)絡(luò)、基于內(nèi)存、可選持久性的鍵值對存儲數(shù)據(jù)庫。
- Redis使用場景:緩存系統(tǒng)(“熱點”數(shù)據(jù):高頻讀、低頻寫)、計數(shù)器、消息隊列系統(tǒng)、排行榜、社交網(wǎng)絡(luò)和實時系統(tǒng)
- Redis數(shù)據(jù)類型:Redis提供的數(shù)據(jù)類型主要分為5種自有類型和一種自定義類型,這5種自有類型包括:String類型、哈希類型、列表類型、集合類型和順序集合類型。
更新緩存模式 Cache aside這是最常用最常用的pattern了。其具體邏輯如下:
- 失效:應(yīng)用程序先從cache取數(shù)據(jù),沒有得到,則從數(shù)據(jù)庫中取數(shù)據(jù),成功后,放到緩存中。
- 命中:應(yīng)用程序從cache中取數(shù)據(jù),取到后返回。
- 更新:先把數(shù)據(jù)存到數(shù)據(jù)庫中,成功后,再讓緩存失效。
更新問題
- 我們知道,在 springboot 1.5.x版本的默認的Redis客戶端是 Jedis實現(xiàn)的,需要導(dǎo)入jedis依賴,而springboot 2.x版本中默認客戶端是用 lettuce實現(xiàn)的,需要導(dǎo)入spring-boot-starter-data-redis依賴。這兩種方式使用的都是 TCP協(xié)議??梢岳斫鉃椋涸蹅兺ㄟ^程序是不能直接連接 Redis,得利用客戶端工具才能進行連接。比較常用的有兩種:Jedis、Lettuce。既然 Lettuce 和 Jedis 的都是連接 Redis Server 的客戶端,那么它們有什么區(qū)別呢?
- Jedis使用直連方式連接Redis Server,在多線程環(huán)境下存在線程安全問題, 因此需要增加連接池來解決線程安全的問題,同時可以限制redis客戶端的數(shù)量, 但這種直連方式基于傳統(tǒng)I/O模式,是阻塞式傳輸。
- 而 Lettuce 是 一種可伸縮,線程安全,完全非阻塞的Redis客戶端,底層基于netty通信,我們知道netty是基于NIO的非阻塞通信, 天生支持高并發(fā),因此在在多線程環(huán)境下不存在線程安全問題,一個連接實例就可以滿足多線程環(huán)境下的并發(fā)訪問, 當(dāng)然實例不夠的情況下也可以按需增加實例,保證伸縮性。
- 下面我們通過源碼的方式解析springboot是如何通過lettuce方式連接redis server的,以及springboot操作redis的底層原理。
?一:環(huán)境配置
1.1: 在pom.xml文件中添加依賴
這里說說為什么要添加 org.apache.commons 依賴,如果不加,它會報錯:Caused by: java.lang.ClassNotFoundException: org.apache.commons.pool2.impl.GenericObjectPoolConfig
<dependencies> <!-- SpringBoot集成Redis的起步依賴 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <version>1.4.7.RELEASE</version> </dependency> <!--lettuce 依賴commons-pool--> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.8.0</version> </dependency> </dependencies>
1.2:配置SpringBoot核心配置文件application.properties
yml文件格式
spring: redis: open: true # 是否開啟redis緩存 true開啟 false關(guān)閉 database: 0 host: 127.0.0.1 port: 3304 password: 123456 # 密碼(默認為空) timeout: 6000ms # 連接超時時長(毫秒) expire: 3600 #7天不過期 lettuce: pool: max-active: 100 # 連接池最大連接數(shù)(使用負值表示沒有限制) max-wait: -1ms # 連接池最大阻塞等待時間(使用負值表示沒有限制) max-idle: 20 # 連接池中的最大空閑連接 min-idle: 5 # 連接池中的最小空閑連接
properties文件格式
#Redis ##Redis數(shù)據(jù)庫索引 spring.redis.database=0 ##Redis服務(wù)器地址 spring.redis.host=127.0.0.1 ## Redis服務(wù)器連接端口 spring.redis.port=3304 ## 連接超時時間(毫秒) spring.redis.timeout=3 ## Redis服務(wù)器連接密碼(默認為空) spring.redis.password=135246 ## 連接池中的最大連接數(shù) (使用復(fù)數(shù)則標(biāo)識沒有限制) 默認 8 spring.redis.pool.max.active=100 ## 連接池最大阻塞等待時間(使用負值表示沒有限制)默認 -1 spring.redis.pool.max.wait=-1 ## 連接池中的最大空閑連接 默認 8 spring.redis.pool.max.idle=20 ## 連接池中的最小空閑連接 默認 0 spring.redis.pool.max.idle=0
二:在Config文件夾中創(chuàng)建RedisConfig配置文件類
RedisTemplate 是 Spring 操作 Redis 的重點內(nèi)容。 RedisTemplate是一個強大的類,首先它會自動從 RedisConnectionFactory 工廠中獲取連接,然后執(zhí)行對應(yīng)的 Redis命令,提供了redis各種操作、異常處理及序列化,支持發(fā)布訂閱,并對spring 3.1 cache進行了實現(xiàn),在最后還會關(guān)閉 Redis 的連接。
2.1:RedisTemplate中的幾個角色:
- RedisSerializer:由于與Redis服務(wù)器的通信一定是使用字節(jié)數(shù)組完成的,所以RedisSerializer是將Java對象編碼解碼的組件
- RedisOperations:封裝了一些Redis操作
- XXXOperations:封裝了指定類型或功能的數(shù)據(jù)的操作,如ZSetOperations
2.2:為什么要自定義序列化:
RedisTemplate操作時,默認會采用jdkSerializable序列化機制,使得插入的值在redis客戶端看來會有亂碼 類似于: "\xac\ced\x00\x05t\x00\x03key" ,所以解決這個問題就需要修改默認的序列化規(guī)則。
2.2.1:Spring 中提供了以下幾個序列化器:
- Jackson2JsonRedisSerializer
- JdkSerializationRedisSerializer
- OxmSerializer
- StringRedisSerializer
- GenericToStringRedisSerializer
- GenericJackson2JsonRedisSerializer
本章使用的是StringRedisSerializer, String序列化方式。
RedisConfig 所在結(jié)構(gòu)地址:
package com.lizexin.springbootdemo.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.*; import org.springframework.data.redis.serializer.StringRedisSerializer; /** * 項目名稱:springboot-demo * 類名稱:RedisConfig * 類描述:Redis配置 * 創(chuàng)建時間:2023/08/04 * @author lzx * @version v1.0 */ @Configuration public class RedisConfig { @Autowired private RedisConnectionFactory factory; @Bean public RedisTemplate<String, Object> redisTemplate() { // 將template 泛型設(shè)置為 <String, Object> RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); // 使用 String 序列化方式,序列化 KEY。 redisTemplate.setKeySerializer(new StringRedisSerializer()); // 使用 String 序列化方式,序列化 VALUE。 redisTemplate.setValueSerializer(new StringRedisSerializer()); // 使用 String 序列化方式,序列化 HashKEY。 redisTemplate.setHashKeySerializer(new StringRedisSerializer()); // 使用 String 序列化方式,序列化 ValueKEY。 redisTemplate.setHashValueSerializer(new StringRedisSerializer()); // 配置連接工廠 redisTemplate.setConnectionFactory(factory); return redisTemplate; } /** * HashOperations * 操作 Hash 類型數(shù)據(jù) **/ @Bean public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) { return redisTemplate.opsForHash(); } /** * HashOperations * 操作 String 類型數(shù)據(jù) **/ @Bean public ValueOperations<String, String> valueOperations(RedisTemplate<String, String> redisTemplate) { return redisTemplate.opsForValue(); } /** * HashOperations * 操作 List 類型數(shù)據(jù) **/ @Bean public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) { return redisTemplate.opsForList(); } /** * HashOperations * 操作 Set 類型數(shù)據(jù) **/ @Bean public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) { return redisTemplate.opsForSet(); } /** * HashOperations * 操作 SortedSet 類型數(shù)據(jù) **/ @Bean public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) { return redisTemplate.opsForZSet(); } }
四:封裝Redis Utils工具包
Redis工具包分為三個類
1:RedisUtils.java Redis方法類主要記錄對redis的一些操作,增刪改查等。
2:RedisKeys.java Redis自定義Key類,自定義配置,對redis操作時好分辨哪個key的數(shù)據(jù)
3:UserRedis.java 封裝類,將RedisUtils和RedisKey進行封裝,用戶直接操作此類
redis 工具包 所在結(jié)構(gòu)地址:
4.1:RedisUtils.java
package com.lizexin.springbootdemo.utils.redis; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.*; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.concurrent.TimeUnit; /** * 項目名稱:springboot-demo * 類名稱:RedisUtils * 類描述:Redis工具類 * 創(chuàng)建時間:2023/08/04 * @author lzx * @version v1.0 */ @Component public class RedisUtils { /**日志*/ private static final Logger logger = LoggerFactory.getLogger(RedisUtils.class); @Autowired private RedisTemplate<String, Object> redisTemplate; @Autowired private ValueOperations<String, String> valueOperations; @Autowired private HashOperations<String, String, Object> hashOperations; @Autowired private ListOperations<String, Object> listOperations; @Autowired private SetOperations<String, Object> setOperations; @Autowired private ZSetOperations<String, Object> zSetOperations; /**默認過期時長,單位: 秒*/ public final static long DEFAULT_EXPIRE = 60 * 10; /**從配置文件獲取 默認過期時長*/ @Value("${spring.redis.expire}") public long expire; /**不設(shè)置過期時長 */ public final static long NOT_EXPIRE = -1; /**它可以幫助我們快速的進行各個類型和Json類型的相互轉(zhuǎn)換*/ private static final ObjectMapper MAPPER = new ObjectMapper(); /**給指定key設(shè)置固定時間的有效期*/ public void expireAt(String key,Date date){ redisTemplate.expireAt(key,date); } /**根據(jù)指定的key,獲取過期時間*/ public long getExpire(String key) { return redisTemplate.getExpire(key, TimeUnit.SECONDS);} /**判斷key是否存在*/ public boolean hasKey(String key) { try { return redisTemplate.hasKey(key); } catch (Exception e) { e.printStackTrace(); return false; } } /** * 刪除緩存, @param key可以傳一個值 或多個 * 該注解屏蔽某些編譯時的警告信息 * */ @SuppressWarnings("unchecked") public void delete(String... key) { if (key != null && key.length > 0) { if (key.length == 1) { redisTemplate.delete(key[0]); } else { redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key)); } } } /**將Object值放如緩存并設(shè)置默認時間,調(diào)用下一個方法將值轉(zhuǎn)為JSON字符串*/ public void set(String key, Object value){ set(key, value, DEFAULT_EXPIRE); } /**將Object值轉(zhuǎn)為JSON字符串放入緩存,并設(shè)置過期時長*/ public void set(String key, Object value, long expire){ valueOperations.set(key, objectToJson(value)); if(expire != NOT_EXPIRE){ redisTemplate.expire(key, expire, TimeUnit.SECONDS); } } /**根據(jù)key和泛型獲取值, 調(diào)用下一個get方法*/ public <T> T get(String key, Class<T> clazz) { return get(key, clazz, NOT_EXPIRE); } /**根據(jù)key鍵獲取值并轉(zhuǎn)為對象 并重新設(shè)置過期時間*/ public <T> T get(String key, Class<T> clazz, long expire) { String value = valueOperations.get(key); if(expire != NOT_EXPIRE){ redisTemplate.expire(key, expire, TimeUnit.SECONDS); } //將Json字符串轉(zhuǎn)換為bean對象 return value == null ? null : fromJson(value, clazz); } /**根據(jù)key鍵獲取值返回為String*/ public String get(String key, long expire) { String value = valueOperations.get(key); if(expire != NOT_EXPIRE){ redisTemplate.expire(key, expire, TimeUnit.SECONDS); } return value; } /*根據(jù)key獲取值*/ public String get(String key) { return get(key, NOT_EXPIRE); } /**Object轉(zhuǎn)換為JSON字符串,在存reid的時候調(diào)用此方法*/ private String objectToJson(Object object){ if(object instanceof Integer || object instanceof Long || object instanceof Float || object instanceof Double || object instanceof Boolean || object instanceof String){ return String.valueOf(object); } return JSONUtil.toJsonStr(object); } /**JSON字符串, 轉(zhuǎn)成javaBean對象*/ private <T> T fromJson(String json, Class<T> clazz){ return JSONUtil.toBean(json, clazz); //return JSON.parseObject(json,clazz); } /**將JsonObject轉(zhuǎn)為實體類對象,轉(zhuǎn)換異常將被拋出*/ public static <T> T fromJsonToBean(JSONObject json, Class<T> beanClass) { return null == json ? null : json.toBean(beanClass); } /**將元素添加到指定set集合中*/ public void addToSet(String key,String member){ redisTemplate.opsForSet().add(key,member); } /**批量添加到指定set集合中*/ public void addBatchToSet(String key,List<String> memberList) { Object[] members = memberList.toArray(); redisTemplate.opsForSet().add(key,members); } /**統(tǒng)計指定set的長度,當(dāng)指定key的set不存在時,返回null*/ public Long countForSet(String key){ return redisTemplate.opsForSet().size(key); } /**只有當(dāng)key不存在時才設(shè)置key的值,并返回true;當(dāng)key存在時不修改key的值,并返回false。*/ public Boolean isMember(String value){ return setOperations.isMember(RedisKeys.AutoKey,value); } /**向集合添加值并設(shè)置過期時間*/ public Long addSetDataExpire(String value,String name,long expire){ Long addSet = setOperations.add(name,value); if(expire != NOT_EXPIRE){ redisTemplate.expire(name, expire, TimeUnit.SECONDS); } return addSet; } /**向右邊批量添加元素*/ public boolean addrightPushAll(String key, List<Object> value) { boolean var4; try { this.redisTemplate.opsForList().rightPushAll(key, value); boolean var3 = true; return var3; } catch (Exception var8) { logger.error("", var8); var4 = false; } finally { this.close(); } return var4; } /** * 獲取泛型的Collection Type * @param collectionClass 泛型的Collection * @param elementClasses 元素類 * @return JavaType Java類型 * @since 1.0*/ public static JavaType getCollectionType(Class<?> collectionClass, Class<?>... elementClasses) { return MAPPER.getTypeFactory().constructParametricType(collectionClass, elementClasses); } private void close() { RedisConnectionUtils.unbindConnection(this.redisTemplate.getConnectionFactory()); } }
4.2:RedisKeys.java
package com.zhangtao.moguding.province.utils.redis; /** * 項目名稱:user-center-service * 類名稱:RedisKeys * 類描述:redis所有的key * 創(chuàng)建時間:2023/7/27 * * @author lzx * @version v1.0 */ public class RedisKeys { //最大蘑菇號的key public final static String MAX_MOGUNO_KEY = "moguding:user:max_mogu_no"; //短信驗證碼的key public static String getSmsCodeKey(String key,Integer type){ return "moguding:user:smsCode:" + key+":"+type; } //權(quán)限列表 public final static String PERMISSIONS_USERAUTH_KEY = "moguding:permissions:permissions_userauth_list:"; //參數(shù)配置 public static String getUserConfigKey(String... key){ return "moguding:user:config:" + key; } //用戶Token public final static String AUTH_TOKEN_KEY = "moguding:user:authToken:"; //authtoken的key web端 public static String getAuthToken(String type,String userid){ if("web".equals(type)){ return AUTH_TOKEN_KEY+type+":" + userid; }else { return getAuthToken(userid); } } //authtoken的key app端 public static String getAuthToken(String userid){ return AUTH_TOKEN_KEY+ userid; } //緩存活躍蘑菇號key的 public final static String ACTIVE_MOGU_NO= "moguding:user:active:"; //緩存今日學(xué)校簽到排行榜 public final static String SCHOOL_SIGN_RANK= "moguding:school:sign:rank"; //學(xué)校統(tǒng)計(實時發(fā)送【考勤,上崗,周報】) public final static String SCHOOL_COUNT= "moguding.school.count"; //自動報告key public final static String AutoKey = "autoReport_set"; //30天最后一次考勤 public final static String LastSign = "moguding.last.sign"; //省平臺基礎(chǔ)數(shù)據(jù) public static String getProvinceConfigKey(String key){ return "moguding:province:config:" + key; } }
4.3:UserRedis.java
package com.zhangtao.moguding.province.utils.redis; import com.zhangtao.moguding.province.entity.UserConfigEntity; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.List; /** * 項目名稱:user-center-service * 類名稱:UserRedis * 類描述:UserRedis * 創(chuàng)建時間:2019/5/27 * @author lzx * @version v1.0 */ /* *將RedisUtils的set方法和RedisKeys的key 封裝到一起 * */ @Component public class UserRedis { @Autowired private RedisUtils redisUtils; public void set(String key,String value) { if(key == null){ return ; } String redisKey = RedisKeys.getUserConfigKey(key); redisUtils.set(redisKey, value,redisUtils.expire); } public void delete(String key) { if(key == null){ return ; } String redisKey = RedisKeys.getUserConfigKey(key); redisUtils.delete(redisKey); } public String get(String key){ if(key == null){ return null; } String redisKey = RedisKeys.getUserConfigKey(key); return redisUtils.get(redisKey); } public UserConfigEntity getObject(String key){ if(key == null){ return null; } String redisKey = RedisKeys.getUserConfigKey(key); return redisUtils.get(redisKey, UserConfigEntity.class); } //向Redis添加值,設(shè)置默認過期時長 7天, set方法將value進行序列化(轉(zhuǎn)為JSON字符串) /* public void set(String key,Object value) { if(key == null){ return ; } String redisKey = RedisKeys.getRedisTestKey(key); redisUtils.set(redisKey, value,redisUtils.expire); } public <T> T get(String key, Class<T> clazz){ if(key == null){ return null; } String redisKey = RedisKeys.getRedisTestKey(key); return redisUtils.get(redisKey,clazz); } //判斷Redis測試key是否存在 public boolean hasKey(String key){ if(key == null){ return false; } String redisKey = RedisKeys.getRedisTestKey(key); return redisUtils.hasKey(redisKey); };*/ //將今日活躍用戶的蘑菇號批量存進redis指定Set集合中 public void addUserMoguNosToSet(List<String> moguNos){ redisUtils.addBatchToSet(RedisKeys.ACTIVE_MOGU_NO,moguNos); } //將今日活躍用戶的蘑菇號緩存Set集合清空 public void deleteForCacheUserMoguNo(){ redisUtils.delete(RedisKeys.ACTIVE_MOGU_NO); } //判斷Redis測試key是否存在 public boolean hasKey(String key){ if(key == null){ return false; } String redisKey = RedisKeys.getProvinceConfigKey(key); return redisUtils.hasKey(redisKey); }; //從redis中統(tǒng)計活躍用戶數(shù)量 public int countActiveUser(){ Long Lnum = redisUtils.countForSet(RedisKeys.ACTIVE_MOGU_NO); if(Lnum==null){ return 0; }else { return Lnum.intValue(); } } //省級平臺獲取redisKey public String getProvinceKey(String key){ if(key == null){ return null; } String redisKey = RedisKeys.getProvinceConfigKey(key); return redisUtils.get(redisKey); } //省級平臺向redis插入數(shù)據(jù) public void setProvinceDataToRedis(String key,String list){ String keys = RedisKeys.getProvinceConfigKey(key); //配置文件默認保留時長 redisUtils.setRedis(keys,list,redisUtils.expire); } }
五:流程實現(xiàn)
模擬SpringBoot項目結(jié)構(gòu)調(diào)用
1.RedisTestController
package com.lizexin.springbootdemo.Controller; import com.lizexin.springbootdemo.entity.Item; import com.lizexin.springbootdemo.service.RedisTestService; import com.zhangtao.common.dto.response.BaseResponse; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @program: springboot-demo * @author: lzx * @Time: 2023/8/9 16:35 * @description: Redis測試接口 * @version: v1.0 */ @RestController @Api(tags = {"Redis測試接口"},produces = "RedisTest_controller") @RequestMapping("/redis") public class RedisTestController { @Autowired RedisTestService redisTestService; private Logger logger = LoggerFactory.getLogger(RedisTestController.class); @ApiOperation(value = "Redis測試,將對象插入緩存",notes = "") @RequestMapping("/v1/test") public BaseResponse redisInsertBeanController(@RequestBody Item item){ return redisTestService.redisInsertBeanService(item); } @ApiOperation(value = "Redis測試,將List插入緩存",notes = "") @RequestMapping("/v2/test") public BaseResponse redisInsertListController(@RequestBody Item item){ return redisTestService.redisInsertListService(item); } @ApiOperation(value = "Redis測試,將Map<String,Set<String>>插入緩存,取出來轉(zhuǎn)Map<String,JsonArry>",notes = "") @RequestMapping("/v3/test") public BaseResponse redisInsertMapController(@RequestBody Item item){ return redisTestService.redisInsertMapService(item); } }
2.RedisTestService
package com.lizexin.springbootdemo.service; import com.lizexin.springbootdemo.entity.Item; import com.zhangtao.common.dto.response.BaseResponse; /** * @program: springboot-demo * @author: lzx * @Time: 2023/8/9 22:55 * @description: Redis測試接口Service * @version: v1.0 */ public interface RedisTestService { BaseResponse redisInsertBeanService( Item item); BaseResponse redisInsertListService( Item item); BaseResponse redisInsertMapService( Item item); }
3.RedisTestServiceImpl
package com.lizexin.springbootdemo.service.impl; import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSONArray; import com.lizexin.springbootdemo.entity.Item; import com.lizexin.springbootdemo.service.RedisTestService; import com.lizexin.springbootdemo.utils.*; import com.lizexin.springbootdemo.utils.redis.UserRedis; import com.zhangtao.common.dto.response.BaseResponse; import com.zhangtao.common.dto.response.ObjectResponse; import io.swagger.annotations.ApiOperation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.*; import java.util.stream.Collectors; /** * @program: springboot-demo * @author: lzx * @Time: 2023/08/9 22:58 * @description: test * @version: v1.0 */ @Service public class RedisTestServiceImpl implements RedisTestService { @Autowired UserRedis userRedis; private static final Logger logger = LoggerFactory.getLogger(RedisTestServiceImpl.class); @Override @ApiOperation( "通過key得到值并重新設(shè)置過期時間,若值不存在則重新插入緩存。"+ "set方法封裝了 JSONUtil.toJsonStr"+ "get帶泛型的方法封裝了JSONUtil.toBean " ) public BaseResponse redisInsertBeanService(Item item) { String redisKey= "redisInsertBeanService"; System.out.println(redisKey); //判斷key值是否存在,如果存在則優(yōu)先取緩存 if (userRedis.hasKey(redisKey)){ Item jsonString= userRedis.get(redisKey,Item.class); logger.info("存在值"); logger.info(jsonString.toString()); return ObjectResponse.resObj(jsonString); }else{ //不存在則緩存 Item item1= AttributeData.list9(); logger.info("不存在值 插入"); userRedis.set(redisKey,item1); return ObjectResponse.ok(); } } @Override @ApiOperation("get方法不帶泛型默認返回Json字符串,需要自行反序列化") public BaseResponse redisInsertListService(Item item) { //通過key得到值, String redisKey = "redisInsertListService"; System.out.println(redisKey); //判斷key值是否存在,如果存在則優(yōu)先取緩存 if (userRedis.hasKey(redisKey)){ List<Item> list = JSONArray.parseArray(userRedis.get(redisKey),Item.class); logger.info("存在值"); logger.info(list.toString()); return ObjectResponse.resObj(list); }else{ //不存在則緩存 List<Item> list= AttributeData.list8(); logger.info("不存在值 插入"); userRedis.set(redisKey,list); return ObjectResponse.ok(); } } @Override @ApiOperation("") public BaseResponse redisInsertMapService(Item item) { //通過key得到值, String redisKey= "redisInsertMapService"; System.out.println(redisKey); //判斷key值是否存在,如果存在則優(yōu)先取緩存 if (userRedis.hasKey(redisKey)){ String jsonString= userRedis.get(redisKey); //可以通過JSonString轉(zhuǎn)對象方法把Vlue值從Set轉(zhuǎn)為JsonArray Map<String,JSONArray> arrayMap= JSONUtil.toBean(jsonString,Map.class); logger.info("存在值"); logger.info(arrayMap.toString()); return ObjectResponse.resObj(arrayMap); }else{ //不存在則緩存 List<Item> list= AttributeData.list10(); //根據(jù)key轉(zhuǎn)map,之后將Value換成set集合 //將集合添加至Map 指定參數(shù)作為key Map<String,List<Item>> map = new HashMap(); Map<String,Set<String>>setMap =new HashMap<>(); map = list.stream().collect(Collectors.groupingBy(Item::getName,Collectors.toList())); for (Map.Entry<String,List<Item>> key:map.entrySet()){ Set<String> set = new HashSet<>(); key.getValue().forEach(c->{ set.add(c.getValue()); }); setMap.put(key.getKey(), set); } logger.info("不存在值 插入"); userRedis.set(redisKey,setMap); return ObjectResponse.ok(); } } }
4.AttributeData
package com.lizexin.springbootdemo.utils; import com.lizexin.springbootdemo.dto.CommonInterfaceDto; import com.lizexin.springbootdemo.dto.InformationDatasDto; import com.lizexin.springbootdemo.dto.export.ExportGxySchoolFlowDto; import com.lizexin.springbootdemo.entity.Item; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @program: springboot-demo * @author: lzx * @Time: 2023/8/9 22:55 * @description: 常用數(shù)據(jù)集 * @version: v1.0 */ public class AttributeData { public static List<Map<String,Object>> list1 (){ //構(gòu)建List集合1 List<Map<String,Object>> list1 = new ArrayList<>(); Map<String,Object> data=new HashMap<>(); data.put("userId","100001"); data.put("userName","唐僧"); list1.add(data); data=new HashMap<>(); data.put("userId","100002"); data.put("userName","八戒"); list1.add(data); data=new HashMap<>(); data.put("userId","100003"); data.put("userName","悟空"); list1.add(data); data=new HashMap<>(); data.put("userId","100004"); data.put("userName","沙僧"); list1.add(data); return list1; } public static List<Map<String,Object>> list2(){ Map<String,Object> data=new HashMap<>(); List<Map<String,Object>> list2 = new ArrayList<>(); data=new HashMap<>(); data.put("userId","100001"); data.put("gender","男"); data.put("age",20); list2.add(data); data=new HashMap<>(); data.put("userId","100002"); data.put("gender","雄"); data.put("age",1000); list2.add(data); data=new HashMap<>(); data.put("userId","100003"); data.put("gender","雄"); data.put("age",600); list2.add(data); data=new HashMap<>(); data.put("userId","100004"); data.put("gender","男"); data.put("age",800); list2.add(data); return list2; } public static List<InformationDatasDto> list3(){ List<InformationDatasDto> list = new ArrayList<>(); InformationDatasDto info = new InformationDatasDto(); info.setStudentId("10000"); info.setStudent_name("張三"); list.add(info); info = new InformationDatasDto(); info.setStudentId("10001"); info.setStudent_name("里李四"); list.add(info); info = new InformationDatasDto(); info.setStudentId("10002"); info.setStudent_name("王五"); list.add(info); info = new InformationDatasDto(); info.setStudentId("10003"); info.setStudent_name("趙六"); list.add(info); info = new InformationDatasDto(); info.setStudentId("10004"); info.setStudent_name("馬七"); list.add(info); return list; } public static List<InformationDatasDto> list4(){ List<InformationDatasDto> list = new ArrayList<>(); InformationDatasDto info = new InformationDatasDto(); info.setStudentId("北京"); info.setStudent_name("張三"); list.add(info); info = new InformationDatasDto(); info.setStudentId("北京省"); info.setStudent_name("里李四"); list.add(info); info = new InformationDatasDto(); info.setStudentId("湖北省"); info.setStudent_name("王五"); list.add(info); info = new InformationDatasDto(); info.setStudentId("湖北"); info.setStudent_name("趙六"); list.add(info); info = new InformationDatasDto(); info.setStudentId("海南"); info.setStudent_name("馬七"); list.add(info); return list; } public static List<ExportGxySchoolFlowDto> list5(){ List<ExportGxySchoolFlowDto> list = new ArrayList<>(); ExportGxySchoolFlowDto info = new ExportGxySchoolFlowDto(); info.setSchoolName("齊齊哈爾大學(xué)"); info.setDatas("黑龍江省"); info.setValue(10); list.add(info); info = new ExportGxySchoolFlowDto(); info.setSchoolName("齊齊哈爾大學(xué)"); info.setDatas("黑龍江"); info.setValue(20); list.add(info); info = new ExportGxySchoolFlowDto(); info.setSchoolName("齊齊哈爾大學(xué)"); info.setDatas("黑龍江省哈爾濱市"); info.setValue(20); list.add(info); info = new ExportGxySchoolFlowDto(); info.setSchoolName("齊齊哈爾大學(xué)"); info.setDatas("甘肅省"); info.setValue(20); list.add(info); info = new ExportGxySchoolFlowDto(); info.setSchoolName("哈爾濱大學(xué)"); info.setDatas("黑龍江"); info.setValue(20); list.add(info); info = new ExportGxySchoolFlowDto(); info.setSchoolName("武漢職業(yè)大學(xué)"); info.setDatas("北京市"); info.setValue(10); list.add(info); info = new ExportGxySchoolFlowDto(); info.setSchoolName("黑河市大學(xué)"); info.setDatas("北京"); info.setValue(10); list.add(info); return list; } public static List<CommonInterfaceDto.ItemBatchDataDto> list6(){ List<CommonInterfaceDto.ItemBatchDataDto> list =new ArrayList<>(); CommonInterfaceDto.ItemBatchDataDto item1 =new CommonInterfaceDto.ItemBatchDataDto(); item1.setSchoolName("雙高校"); item1.setData(10); item1.setBatchName("19年"); list.add(item1); CommonInterfaceDto.ItemBatchDataDto item2 =new CommonInterfaceDto.ItemBatchDataDto(); item2.setSchoolName("雙高校"); item2.setData(20); item2.setBatchName("20年"); list.add(item2); CommonInterfaceDto.ItemBatchDataDto item3 =new CommonInterfaceDto.ItemBatchDataDto(); item3.setSchoolName("雙高校"); item3.setData(30); item3.setBatchName("21年"); list.add(item3); CommonInterfaceDto.ItemBatchDataDto item4 =new CommonInterfaceDto.ItemBatchDataDto(); item4.setSchoolName("雙高校"); item4.setData(40); item4.setBatchName("22年"); list.add(item4); return list; } public static List<CommonInterfaceDto.ItemBatchDataDto> list7(){ List<CommonInterfaceDto.ItemBatchDataDto> list =new ArrayList<>(); CommonInterfaceDto.ItemBatchDataDto item1 =new CommonInterfaceDto.ItemBatchDataDto(); item1.setSchoolName("鄭州經(jīng)貿(mào)學(xué)院"); item1.setData(60); item1.setBatchName("19年"); list.add(item1); CommonInterfaceDto.ItemBatchDataDto item2 =new CommonInterfaceDto.ItemBatchDataDto(); item2.setSchoolName("鄭州經(jīng)貿(mào)學(xué)院"); item2.setData(10); item2.setBatchName("22年"); list.add(item2); return list; } public static List<Item> list8(){ List<Item> list =new ArrayList<>(); Item item1 =new Item(); item1.setName("計算機"); item1.setValue(10); list.add(item1); Item item2 =new Item(); item2.setName("會計"); item2.setValue(20); list.add(item2); Item item3 =new Item(); item3.setName("銷售"); item3.setValue(30); list.add(item3); Item item4 =new Item(); item4.setName("老師"); item4.setValue(40); list.add(item4); Item item5 =new Item(); item5.setName("醫(yī)學(xué)"); item5.setValue(40); list.add(item5); Item item6 =new Item(); item6.setName("農(nóng)業(yè)"); item6.setValue(94); list.add(item6); Item item7 =new Item(); item7.setName("工程"); item7.setValue(100); list.add(item7); return list; } public static Item list9(){ Item item7 =new Item(); item7.setName("工程"); item7.setValue(100); return item7; } public static List<Item> list10(){ List<Item> list =new ArrayList<>(); Item item1 =new Item(); item1.setName("河南省"); item1.setValue("鄭州市"); list.add(item1); Item item2 =new Item(); item2.setName("河南省"); item2.setValue("洛陽市"); list.add(item2); Item item3 =new Item(); item3.setName("河南省"); item3.setValue("開封市"); list.add(item3); Item item4 =new Item(); item4.setName("湖北省"); item4.setValue("武漢市"); list.add(item4); Item item5 =new Item(); item5.setName("湖北省"); item5.setValue("襄陽市"); list.add(item5); Item item6 =new Item(); item6.setName("湖北省"); item6.setValue("潛江市"); list.add(item6); Item item7 =new Item(); item7.setName("湖北省"); item7.setValue("荊州市"); list.add(item7); Item item8 =new Item(); item8.setName("北京"); item8.setValue("北京市"); list.add(item8); return list; } }
調(diào)用結(jié)果:
相關(guān)文章
啟動springboot應(yīng)用因未配置數(shù)據(jù)庫報錯的解決方案
這篇文章主要介紹了啟動springboot應(yīng)用因未配置數(shù)據(jù)庫報錯的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11Spring?Boot集成Milvus快速入門demo示例詳解
Milvus是一種高性能向量數(shù)據(jù)庫,支持從筆記本到大型分布式系統(tǒng)的多環(huán)境運行,它以開源和云服務(wù)形式提供,是LFAI & Data Foundation的項目,采用Apache 2.0許可,Milvus特別支持高并行化和解耦的系統(tǒng)架構(gòu),使其能夠隨數(shù)據(jù)增長而擴展,支持各種復(fù)雜搜索功能,滿足企業(yè)級AI應(yīng)用需求2024-09-09Spring、SpringMvc和SpringBoot的區(qū)別及說明
Spring框架提供了全面的Java開發(fā)解決方案,核心包括IOC和AOP,SpringMvc作為其中的WEB層開發(fā)框架,通過復(fù)雜的XML配置管理前端視圖和后臺邏輯,SpringBoot則簡化了配置,專注于微服務(wù)接口開發(fā),支持嵌入式服務(wù)器,提高了開發(fā)效率2024-10-10Spring Boot + Kotlin整合MyBatis的方法教程
前幾天由于工作需要,便開始學(xué)習(xí)了kotlin,java基礎(chǔ)扎實學(xué)起來也還算比較快,對于kotlin這個編程語言自然是比java有趣一些,下面這篇文章主要給大家介紹了關(guān)于Spring Boot + Kotlin整合MyBatis的方法教程,需要的朋友可以參考下。2018-01-01RocketMQ NameServer保障數(shù)據(jù)一致性實現(xiàn)方法講解
這篇文章主要介紹了RocketMQ NameServer保障數(shù)據(jù)一致性實現(xiàn)方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-12-12springboot3+r2dbc響應(yīng)式編程實踐
本文主要介紹了springboot3+r2dbc響應(yīng)式編程實踐,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-02-02