写在前面的话:

此章节分为【基础篇】及【应用篇】,若仅是学习整合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