二十二、springboot整合redis

前言

本篇文章简单介绍springboot2.0中使用spring-boot-starter-data-redis整合redis,并使用fastjson作为redis序列化框架,本实例redis为单机服务,且使用Lettuce连接redis服务器。

Redis 连接池简介

在后面 springboot 整合 redis 的时候会用到连接池,所以这里先来介绍下 Redis中的连接池:

客户端连接 Redis 使用的是 TCP协议,直连的方式每次需要建立 TCP连接,而连接池的方式是可以预先初始化好客户端连接,所以每次只需要从 连接池借用即可,而借用和归还操作是在本地进行的,只有少量的并发同步开销,远远小于新建TCP连接的开销。另外,直连的方式无法限制 redis客户端对象的个数,在极端情况下可能会造成连接泄漏,而连接池的形式可以有效的保护和控制资源的使用。

下面以Jedis客户端为例,再来总结下 客户端直连方式和连接池方式的对比

优点 缺点
直连 简单方便,适用于少量长期连接的场景 1. 存在每次新建/关闭TCP连接开销 2. 资源无法控制,极端情况下出现连接泄漏 3. Jedis对象线程不安全(Lettuce对象是线程安全的)
连接池 1. 无需每次连接生成Jedis对象,降低开销 2. 使用连接池的形式保护和控制资源的使用 相对于直连,使用更加麻烦,尤其在资源的管理上需要很多参数来保证,一旦规划不合理也会出现问题

Jedis和Lettuce的区别在哪?

Jedis 和 Lettuce 是 Java 操作 Redis 的客户端。在 Spring Boot 1.x 版本默认使用的是 jedis
,而在 Spring Boot 2.x 版本默认使用的就是Lettuce。关于 Jedis 跟 Lettuce 的区别如下:

1、Jedis 是直连模式,在多个线程间共享一个 Jedis 实例时是线程不安全的,每个线程都去拿自己的 Jedis 实例,当连接数量增多时,物理连接成本就较高了。

2、Lettuce的连接是基于Netty的,连接实例可以在多个线程间共享,如果你不知道Netty也没事,大致意思就是一个多线程的应用可以使用同一个连接实例,而不用担心并发线程的数量。通过异步的方式可以让我们更好地利用系统资源。

既然有这么大的好处,干脆就用了这个,跟上时代的变化。下面新建一个SpringBootRedis项目,开始整合。

springboot 2.0 通过 lettuce集成Redis服务

  1. pom文件导入依赖

 <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-data-redisartifactId>
        dependency>

application.properties配置文件

# jedis方式连接
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=localhost
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)默认8
spring.redis.jedis.pool.max-active=200
# 连接池最大阻塞等待时间(使用负值表示没有限制)默认-1
spring.redis.jedis.pool.max-wait=-1
# 连接池中的最大空闲连接默认8
spring.redis.jedis.pool.max-idle=10
# 连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=1000


# Lettuce的连接
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=localhost
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)默认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
# 连接超时时间(毫秒)
spring.redis.timeout=1000

创建fastjson的redis序列化类

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;

import java.nio.charset.Charset;

public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> {

    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

    private Class<T> clazz;

    public FastJson2JsonRedisSerializer(Class<T> clazz) {
        super();
        this.clazz = clazz;
    }

    @Override
    public byte[] serialize(T t) throws SerializationException {
        if (t == null) {
            return new byte[0];
        }
        SerializerFeature[] features = new SerializerFeature[]{
                // //是否输出值为null的字段,默认为false
                SerializerFeature.WriteMapNullValue,
                //Enum输出name()或者original,默认为false
                SerializerFeature.WriteEnumUsingToString,
                //List字段如果为null
                SerializerFeature.WriteNullListAsEmpty,
                //全局修改日期格式,默认为false
                SerializerFeature.WriteDateUseDateFormat
        };
        return JSON.toJSONString(t, features).getBytes(DEFAULT_CHARSET);
    }

    @Override
    public T deserialize(byte[] bytes) throws SerializationException {
        if (bytes == null || bytes.length <= 0) {
            return null;
        }
        String str = new String(bytes, DEFAULT_CHARSET);

        return (T) JSON.parseObject(str, clazz);
    }

}

创建redis配置文件


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.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {
    // 注入redis序列化
    @Bean
    public RedisSerializer fastJson2JsonRedisSerializer() {
        return new FastJson2JsonRedisSerializer<>(Object.class);
    }
    @Bean
    public RedisTemplate initRedisTemplate(RedisConnectionFactory redisConnectionFactory, RedisSerializer fastJson2JsonRedisSerializer) throws Exception {
        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        redisTemplate.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化方式
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson
        redisTemplate.setValueSerializer(fastJson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson
        redisTemplate.setHashValueSerializer(fastJson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

}

创建用户实体类

public class User implements Serializable {
    private Long id;
    private String guid;
    private String name;
    private String age;
    private Date createTime;

    public User() {
    }
	// 省略get set
}

创建接口测试

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.Date;

@RequestMapping("/redis")
@RestController
public class RedisController {
    private static int ExpireTime = 60;   // redis中存储的过期时间60s

    @Resource
    private RedisUtil redisUtil;

    @RequestMapping("set")
    public boolean redisset(String key, String value) {
        User user = new User();
        user.setId(Long.valueOf(1));
        user.setGuid(String.valueOf(1));
        user.setName("张三");
        user.setAge(String.valueOf(20));
        user.setCreateTime(new Date());

        //return redisUtil.set(key,user,ExpireTime);

        return redisUtil.set(key, user);
    }

    @RequestMapping("get")
    public Object redisget(String key) {
        return redisUtil.get(key);
    }

    @RequestMapping("expire")
    public boolean expire(String key) {
        return redisUtil.expire(key, ExpireTime);
    }
}

测试

请求接口:http://localhost:8080/redis/set?key=aaa,在redis客户端可以看到数据说明序列化保存成功。

二十二、springboot整合redis_第1张图片

请求接口:http://localhost:8080/redis/get?key=aaa,若成功看到返回数据,说明redis反序列化成功。

二十二、springboot整合redis_第2张图片

你可能感兴趣的:(springboot)