写在前面的话:
此章节分为【基础篇】及【应用篇】,若仅是学习整合redis,参阅【基础篇】即可。
在SpringBoot2.x中,默认采用Lettuce客户端来连接Redis服务端,不使用连接池。spring容器是自动的生成了RedisTemplate<Object,Object>,可以直接注入,根据使用情况进行适当的序列化即可。此为基础篇。
直连redis的方式,即每次连接都创建新的连接。当并发量剧增时,这会带来性能上开销,同时由于没有对连接数进行限制,则可能使服务器崩溃导致无法响应。所以一般会建立连接池,事先初始化一组连接,供需要redis连接的线程取用。(本篇仅介绍<String, String>的序列化操作,为下一章的整合token做准备)。此为应用篇。
关于序列化器:大多实际使用中,一般不会直接使用RedisTemplate<Object,Object>,而是会对key、value进行适当的序列化。如:存储token,将会序列化为<String, String>;将登陆用户缓存到redis,将会序列化为<String, User>。
关于redis的安装、配置,以及远程连接出现的一系列问题,参阅Linux下Redis的安装、配置 及 redis远程连接失败的问题
——业精于勤荒于嬉,行成于思毁于随
一、前情概要:
二、环境介绍:
开发平台:windows
开发工具:IDEA
测试工具:POSTMAN
SpringBoot 2.x + mysql 8.0 + mybatis-plus 3.1.1
三、基础篇:
1、pom文件添加依赖:(在上一章的基础上添加)
<!--redis--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
2、配置文件:
# RedisProperties # redis server config spring.redis.database=1 spring.redis.host= #ip地址# spring.redis.password= #密码# spring.redis.port= #端口(redis默认端口为6379)# #redis pool config spring.redis.jedis.pool.max-active=30 #连接池最大阻塞等待时间(使用负值表示没有限制) spring.redis.jedis.pool.max-wait=-1ms #空闲连接 spring.redis.jedis.pool.min-idle=5 spring.redis.jedis.pool.max-idle=20
3、spring容器是自动的生成了RedisTemplate<Object,Object>,可以直接注入。直接进行测试:
/** * 测试redis * * @author Francis * @version 1.0 * @date 2019-07-05 9:43 */ public class Demo1 extends DemoApplicationTests{ @Autowired RedisTemplate<Object, Object> redisTemplate; @Autowired UserService userService; /** * 【基础篇】redis 测试 -- 1、字符串键值对存入 */ @Test public void method1(){ //设置 key-value 序列化器 redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new StringRedisSerializer()); redisTemplate.opsForValue().set("key", "测试redis是否联通"); } /** * 【基础篇】redis 测试 -- 2、字符串键值对取出 */ @Test public void method2(){ //设置 key-value 序列化器 redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new StringRedisSerializer()); String value = (String) this.redisTemplate.opsForValue().get("key"); System.out.println(value); } /** * 【基础篇】redis 测试 -- 3、对象的存入(仅demo,占用空间是存入json的5倍以上) * PS:1、对象必须实现序列化接口。2、需对value重新设置序列化器 */ @Test public void method3(){ //设置 key-value 序列化器 redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer()); TSysUser user = userService.list(null).get(0); redisTemplate.opsForValue().set("user", user); } /** * 【基础篇】redis 测试 -- 4、对象的取出 * PS:1、对象必须实现序列化接口。2、需对value重新设置序列化器 */ @Test public void method4(){ //设置 key-value 序列化器 redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer()); TSysUser user = (TSysUser) this.redisTemplate.opsForValue().get("user"); System.out.println(user); } /** * 【基础篇】redis 测试 -- 5、json对象的存入 */ @Test public void method5(){ //设置 key-value 序列化器 redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(TSysUser.class)); TSysUser user = userService.list(null).get(0); redisTemplate.opsForValue().set("userJson", user); } /** * 【基础篇】redis 测试 -- 6、json对象的取出 */ @Test public void method6(){ redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(TSysUser.class)); TSysUser user = (TSysUser) this.redisTemplate.opsForValue().get("userJson"); System.out.println(user); } /** * 【基础篇】redis 测试 -- 7、设定key的同时设定失效时间 */ @Test public void method7(){ //设置 key-value 序列化器 redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new StringRedisSerializer()); redisTemplate.opsForValue().set("key2", "测试失效时间", 10, TimeUnit.SECONDS); } /** * 【基础篇】redis 测试 -- 8、给现有key设置失效时间 */ @Test public void method8(){ //设置 key-value 序列化器 redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new StringRedisSerializer()); redisTemplate.expire("key", 10, TimeUnit.SECONDS); } }
4、由于测试结果截图太占用版面,此处就不放测试结果了。RedisDesktopManager 可用于查看redis存储结果。
四、应用篇
1、pom文件添加依赖:(在上一章基础上添加)
<!--redis--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <exclusions> <exclusion> <groupId>io.lettuce</groupId> <artifactId>lettuce-core</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency>
2、配置文件:【此处为 hostName 基础篇为 host】
# RedisProperties # redis server config spring.redis.database=1 spring.redis.hostName= #ip地址# spring.redis.password= #密码# spring.redis.port= #端口(redis默认端口为6379)# #redis pool config spring.redis.jedis.pool.max-active=30 #连接池最大阻塞等待时间(使用负值表示没有限制) spring.redis.jedis.pool.max-wait=-1ms #空闲连接 spring.redis.jedis.pool.min-idle=5 spring.redis.jedis.pool.max-idle=20
/** * redis 配置类 * * @author Francis * @date 2019-07-05 13:53 */ @Configuration public class RedisConfig { @Bean @ConfigurationProperties(prefix = "spring.redis.jedis.pool") public JedisPoolConfig poolConfig(){ return new JedisPoolConfig(); } @Bean @ConfigurationProperties(prefix = "spring.redis") public JedisConnectionFactory factory(){ JedisConnectionFactory factory = new JedisConnectionFactory(poolConfig()); return factory; } @Bean public RedisTemplate<String, Object> redisTemplate(){ RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(factory()); //初始化为<String, String> template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new StringRedisSerializer()); return template; } }
3、测试:
/** * 测试redis -- 应用篇 * * @author Francis * @version 1.0 * @date 2019-07-05 11:22 */ public class Demo2 extends DemoApplicationTests{ @Autowired RedisTemplate<String, Object> redisTemplate; /** * 【应用篇】redis 测试 -- 1、字符串键值对存入 */ @Test public void method1(){ redisTemplate.opsForValue().set("advanceKey", "测试redis是否联通"); } /** * 【应用篇】redis 测试 -- 2、字符串键值对取出 */ @Test public void method2(){ String value = (String) this.redisTemplate.opsForValue().get("key"); System.out.println(value); } /** * 若要存储对象或json等,则需要重新序列化Key-Value,此部分与基础篇相同 */ }
五、封装redis工具类
1、注:本小节针对于【应用篇】拓展。
2、工具类代码:
/** * redis 各类存取工具类 * * @author Francis * @version 1.0 * @date 2019-07-05 14:11 */ @Component public class RedisUtils { private static RedisTemplate<String, Object> redisTemplate; @Autowired private RedisTemplate<String, Object> oriRedisTemplate; @PostConstruct public void beforeInit(){ redisTemplate = oriRedisTemplate; } /*********************************************************************************************************** * ****************************************存储 -- 不设置失效时间******************************************* ***********************************************************************************************************/ /** * 字符串键值对 -- 存储-不设置失效时间 * @param key key * @param value value */ public static void save(String key, String value){ validateKeyAndValue(key, value); redisTemplate.opsForValue().set(key, value); } /** * 对象 -- 存储-不设置失效时间 * @param key key * @param t 实体对象 */ public static <T> void save(String key, T t){ validateKeyAndValue(key, t); redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer()); redisTemplate.opsForValue().set(key, t); } /** * json -- 存储-不设置失效时间 * @param key key * @param t value * @param clazz T.class */ public static <T> void save(String key, T t, Class<T> clazz){ validateKeyAndValue(key, t); validateClazz(clazz); redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(clazz)); redisTemplate.opsForValue().set(key, t); } /*********************************************************************************************************** * ****************************************存储 -- 设置失效时间******************************************* ***********************************************************************************************************/ /** * 字符串键值对 -- 存储-设置失效时间 * @param key key * @param value value * @param timeout 失效时间 * @param unit 失效时间单位 */ public static void save(String key, String value, long timeout, TimeUnit unit){ validateKeyAndValue(key, value); validateTimeAndUnit(timeout, unit); redisTemplate.opsForValue().set(key, value, timeout, unit); } /** * 对象 -- 存储-不设置失效时间 * @param key key * @param t 实体对象 * @param timeout 失效时间 * @param unit 失效时间单位 */ public static <T> void save(String key, T t, long timeout, TimeUnit unit){ validateKeyAndValue(key, t); validateTimeAndUnit(timeout, unit); redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer()); redisTemplate.opsForValue().set(key, t, timeout, unit); } /** * json -- 存储-不设置失效时间 * @param key key * @param t value * @param clazz T.class * @param timeout 失效时间 * @param unit 失效时间单位 */ public static <T> void save(String key, T t, Class<T> clazz, long timeout, TimeUnit unit){ validateKeyAndValue(key, t); validateClazz(clazz); validateTimeAndUnit(timeout, unit); redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(clazz)); redisTemplate.opsForValue().set(key, t, timeout, unit); } /*********************************************************************************************************** * *********************************************** 读取 ************************************************** ***********************************************************************************************************/ /** * 字符串键值对 -- 读取 * @param key key */ public static String getKey4String(String key){ validateKey(key); return (String) redisTemplate.opsForValue().get(key); } /** * 对象 -- 读取 * @param key key * @param <T> 返回对象 * @return */ public static <T> T getKey4Pojo(String key, Class<T> clazz){ validateKey(key); validateClazz(clazz); redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer()); return clazz.cast(redisTemplate.opsForValue().get(key)); } /** * 对象json -- 读取 * @param key key * @param clazz t.class() * @param <T> 返回对象 * @return */ public static <T> T getKey4Json(String key, Class<T> clazz){ validateKey(key); validateClazz(clazz); redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(clazz)); return clazz.cast(redisTemplate.opsForValue().get(key)); } /*********************************************************************************************************** * ******************************************* 辅助校验工具 ********************************************** ***********************************************************************************************************/ /** * 校验 key and value * @param key * @param value */ private static void validateKeyAndValue(String key, Object value){ if(StringUtils.isEmpty(key) || StringUtils.isEmpty(value)){ throw new CosyException(CodeMsg.KEY_AND_VALUE_MUST_BE_NOT_EMPTY); } } /** * 校验 key * @param key */ private static void validateKey(String key){ if(StringUtils.isEmpty(key)){ throw new CosyException(CodeMsg.KEY_MUST_BE_NOT_EMPTY); } } /** * 校验 timeout and unit * @param timeout * @param unit */ private static void validateTimeAndUnit(long timeout, TimeUnit unit){ if(StringUtils.isEmpty(timeout) || StringUtils.isEmpty(unit)){ throw new CosyException(CodeMsg.TIME_AND_UNIT_MUST_BE_NOT_EMPTY); } } /** * 校验 class 类 * @param clazz * @param <T> */ private static <T> void validateClazz(Class<T> clazz){ if(StringUtils.isEmpty(clazz)){ throw new CosyException(CodeMsg.CLASS_MUST_BE_NOT_EMPTY); } } }
3、测试代码:
/** * 测试 -- redis 工具类 * * @author Francis * @version 1.0 * @date 2019-07-05 14:27 */ public class Demo3 extends DemoApplicationTests{ @Autowired IUserService userService; /** * 1、 测试 -- 存储 */ @Test public void method1(){ TSysUser user = userService.list(null).get(0); RedisUtils.save("str1", "测试工具类存储"); RedisUtils.save("str2", "测试工具类存储,并设置失效时间", 30, TimeUnit.SECONDS); RedisUtils.save("user1", user); RedisUtils.save("user2", user, 30, TimeUnit.SECONDS); RedisUtils.save("userJson1", user, TSysUser.class); RedisUtils.save("userJson2", user, TSysUser.class, 30, TimeUnit.SECONDS); } /** * 2、 测试 -- 键值对-取出 */ @Test public void method2(){ String str1 = RedisUtils.getKey4String("str1"); String str2 = RedisUtils.getKey4String("str2"); System.out.println(str1); System.out.println(str2); } /** * 3、 测试 -- 对象取出 */ @Test public void method3(){ TSysUser user1 = RedisUtils.getKey4Pojo("user1", TSysUser.class); TSysUser user2 = RedisUtils.getKey4Pojo("user2", TSysUser.class); System.out.println(user1); System.out.println(user2); } /** * 4、 测试 -- json取出并转为对象 */ @Test public void method4(){ TSysUser user1 = RedisUtils.getKey4Json("userJson1", TSysUser.class); TSysUser user2 = RedisUtils.getKey4Json("userJson2", TSysUser.class); System.out.println(user1); System.out.println(user2); } }
六、参考文献
https://yq.aliyun.com/articles/560035?utm_content=m_1000007808