SpringBoot整合Redis(附源码)

191 阅读4分钟

SpringBoot整合Redis

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

Redis是现在最流行的nosql(非关系型数据库)了,因为它是在内存上操作,所以速度快,非常受大家青睐,今天讲讲如何在SpringBoot里整合Redis。

Redis

首先确认自己电脑上有Redis,是不是能见到这个东西呢

image-20201007185019598

如果能用redis的可视化工具RedisDesktopManager查看一下就更稳妥不过,关于RedisDesktopManager的安装和使用可以看我这篇文章

前言

1、Redis在实际应用面很广,可以做缓存、消息队列等。

2、目前流行的Redis集成到Java环境有两种方案,分别是Jedislettuce。老版本中Jedis用的比较多,但是在SpringBoot2.x后官方已经推荐默认lettuce连接了。原因主要是,Jedis虽然线程安全,但占用资源较大,而lettuce基于netty和nio相关实现,性能不但强,而且占用资源更少。

3、我们知道Redis有16个分区(表),如果不配置默认用0号库(第一个)。

4、Redis的默认五个基本类型:String、set、hash、zset(有序集合)、list

5、Spring中的的Redis数据封装有StringRedisTemplate和RedisTemplate

RedisTemplate和StringRedisTemplate的区别:

  • 两者的关系是StringRedisTemplate继承RedisTemplate。

  • 两者的数据是不共通的;也就是说StringRedisTemplate只能管理StringRedisTemplate里面的数据,RedisTemplate只能管理RedisTemplate中的数据。

  • SDR默认采用的序列化策略有两种,一种是String的序列化策略,一种是JDK的序列化策略。

StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。(JdkSerializationRedisSerializer)

RedisTemplate默认采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。(StringRedisSerializer)

6、如果Redis要操作对象,pojo一定要序列化(Serializer)。否则不能和Redis交互。

开始整合

创建新项目

创建一个新的SpringBoot项目

image-20201007190544630

创建时选择Redis依赖,或者创建后导入

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

添加缓存池依赖(如果不配置连接池大小、连接数等可不添加)

		<dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId> commons-pool2</artifactId>
        </dependency>

编写配置文件

application.properties

#SpringBoot所有的配置类,都有一个自动配置类	RedisAutoConfiguration
#自动配置类会绑定一个properties配置文件	RedisProperties

#配置Redis
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=
#密码没有就不写

spring.redis.timeout=10000
#设置超时
spring.cache.type=redis
#将redis设置为缓存


# Redis默认情况下有16个分片,这里配置具体使用的分片,默认是0
spring.redis.database=1
# 连接池最大连接数(使用负值表示没有限制) 默认 8
spring.redis.lettuce.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
spring.redis.lettuce.pool.max-wait=-1
# 连接池中的最大空闲连接 默认 8
spring.redis.lettuce.pool.max-idle=8
# 连接池中的最小空闲连接 默认 0
spring.redis.lettuce.pool.min-idle=0

测试连接

在SpringBootTest类中

@SpringBootTest
class SpringbootRedisTestApplicationTests {

    @Autowired
    RedisTemplate redisTemplate;

    @Test
    void contextLoads() {
        System.out.println(redisTemplate.execute(RedisConnectionCommands::ping));
    }

}

image-20201007192236197

记得启动Redis先啊亲

创建RedisConfig类

为什么SpringBoot有我们还要创建?我们看看自带的RedisAutoConfiguration

image-20201007193054127

可以看到SpringBoot帮我们在容器中生成了两个封装对象,一个是RedisTemplate,还有一个是StringRedisTemplate。但是这个RedisTemplate是<Object,Object>的,显然用的不舒服,我们可以自己整个自定义的配置类来配置RedisTemplate。后面我们也可以测试用自带的和我们自定义的区别。

image-20201007195915118

RedisConfiguration.java

@Configuration
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class RedisConfiguration {
    @Bean
    public RedisTemplate<String, Serializable> redisCacheTemplate(LettuceConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Serializable> template = new RedisTemplate<>();
        GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
        // 设置键(key)的序列化采用StringRedisSerializer。
        template.setKeySerializer(new StringRedisSerializer());
        // 设置值(value)的序列化采用jackson的序列化。
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

}

创建实体类

image-20201007200600951

User.java

package com.feng.springbootredistest.pojo;

import java.io.Serializable;

/**
 * <h3>springboot-redis-test</h3>
 * <p></p>
 *
 * @author : Nicer_feng
 * @date : 2020-10-07 19:23
 **/

public class User implements Serializable {
    private Integer id;
    private String name;
    private String pwd;

    public User(Integer id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}

测试

在SpringBootTest中测试我们的模板

package com.feng.springbootredistest;

import com.feng.springbootredistest.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.connection.RedisConnectionCommands;
import org.springframework.data.redis.core.RedisTemplate;

@SpringBootTest
class SpringbootRedisTestApplicationTests {

    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    RedisTemplate redisCacheTemplate;

    @Test
    void contextLoads() {
        System.out.println(redisTemplate.execute(RedisConnectionCommands::ping));
    }

    @Test
    public void queryUser1(){
        Object user = redisCacheTemplate.opsForValue().get("feng");
        if(user!=null){
            System.out.println((User) user+" 数据在缓存中读到");
        }else{
            //假装去了数据库
            User userFromMysql = new User(1,"feng1","111111");
            redisCacheTemplate.opsForValue().set("feng",userFromMysql);
            System.out.println(userFromMysql+" 从数据库里拿到并存入redis缓存中");
        }
    }

    @Test
    public void queryUser0(){
        Object user = redisTemplate.opsForValue().get("feng");
        if(user!=null){
            System.out.println((User) user+" 数据在缓存中读到");
        }else{
            User userFromMysql = new User(1,"feng0","000000");
            redisTemplate.opsForValue().set("feng",userFromMysql);
            System.out.println(userFromMysql+" 从数据库里拿到并存入redis缓存中");
        }
    }

}

我们这里写了两个test,一个是我们自己封装的Template,一个是SpringBoot自带的,分别使用,看看有什么不同。

SpringBoot自带Template

在这里插入图片描述

自定义的RedisTemplate

GIF 2020-10-7 20-12-55

怎么样,看出区别了吧。主要是我们的json字符串传输问题,代码里我也模拟了redis作为缓存的实际业务情况,controller层的业务也不再赘述,讲到这里基本没啥区别。到这里整合基本结束了。

  • 推荐使用RedisDesktopManager可视化工具实时观察redis内的情况

  • 实体类记得序列化

  • 如果不想配置序列化可以直接使用自带的,但是不利于观察!虽然不影响存取

  • 推荐使用自定义RedisTemplate模板