写在前面的话:
此章节分为【基础篇】及【应用篇】,若仅是学习整合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远程连接失败的问题
——业精于勤荒于嬉,行成于思毁于随
一、前情概要:
SpringBoot从入门到进阶(一):springboot项目的搭建
SpringBoot从入门到进阶(二):整合Mysql+MybatisPlus
二、环境介绍:
开发平台: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