在Spring中配置使用Redis

前言

1、Redis是什么

        Redis是一种运行在内存中的数据库,支持七种数据类型(常用的只有五种)的存储。Redis是一个开源的使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。

2、相关阅读

       在阅读本章之前,读者需要掌握Redis的基本使用:   Redis教程       

       深入了解:  分布式之redis复习精讲

一、 导入依赖

        <!-- 加入Redis的依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <!-- 不依赖Redis的异步客户端lettuce -->
            <exclusions>
                <exclusion>
                    <groupId>io.lettuce</groupId>
                    <artifactId>lettuce-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- 引入Redis的客户端驱动jedis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>

这样我们就引入了Spring对Redis的starter,只是在默认情况下,spring-boot-starter-data-redis(版本2.x)会依赖Lettuce的Redis客户端驱动,而在一般的项目中,我们会使用Jedis,所以在代码中使用<exclusions>元素将其依赖排除了,与此同时引入了Jedis的依赖。

扩展阅读:Redis的三个客户端驱动的比较:Jedis,Redisson,Lettuce

二、配置RedisConnectionFactory

          Spring提供了一个RedisConnectionFactory接口,通过它可以生成一个RedisConnection接口对象,而RedisConnection接口对象是对Redis底层接口的封装。例如,本章使用的Jedis驱动,那么Spring就会提供RedisConnection接口的实现类JedisConnection去封装原有的Jedis(redis.client.jedis.Jedis)对象。所以我们第一步需要先配置RedisConnectionFactory,而配置这个连接工厂主要是配置Redis的连接池(因为Jedis客户端实例不是线程安全的,所以需要通过连接池来使用Jedis。)具体配置如下:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import redis.clients.jedis.JedisPoolConfig;

//在Spring中配置redis
@Configuration
public class RedisConfig {
    //配置Redis连接池
    @Bean
    public JedisPoolConfig jedisPoolConfig(){
        JedisPoolConfig poolConfig=new JedisPoolConfig();
        //最大空闲数
        poolConfig.setMaxIdle(30);
        //最大连接数
        poolConfig.setMaxTotal(50);
        //最大等待毫秒数
        poolConfig.setMaxWaitMillis(2000);
        return poolConfig;
    }
    //配置Redis的连接工厂
    @Bean
    public RedisConnectionFactory redisConnectionFactory(JedisPoolConfig poolConfig){
        JedisConnectionFactory connectionFactory=new JedisConnectionFactory(poolConfig);
        //获取单机的Redis配置
        RedisStandaloneConfiguration standaloneConfiguration=connectionFactory.getStandaloneConfiguration();
        connectionFactory.setHostName("127.0.0.1");
        connectionFactory.setPort(6379);
        //connectionFactory.setPassword("");
        return connectionFactory;
    }
}

这里我们通过配置一个连接池对象来创建RedisConnectionFactory,通过它就能够创建RedisConnection接口对象。但是传统的操作方式是,在使用一条连接时,要先从RedisConnectionFactory工厂获取,然后在使用完成后还要自己关闭它。这是相当繁琐的,还好Spring为了简化开发,提供了RedisTemplate。下面让我们看看,如何配置RedisTemplate进而使用Redis的。

三、配置RedisTemplate

        RedisTemplate是一个强大的类,首先它会自动从RedisConnectionFactory工厂中获取RedisConnection连接,然后执行完对应的Redis命令后,它会自动关闭Redis的连接。

        在上诉RedisConfig 配置类中,加入以下代码,我们就完成了RedisTemplate的配置。

    //配置RedisTemplate
    @Bean
    public RedisTemplate<Object,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
        RedisTemplate<Object,Object> redisTemplate=new RedisTemplate<>();
        //设置redisTemplate的连接工厂
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        return redisTemplate;
    }

四、测试RedisTemplate

下面我们创建个测试类来测试下RedisTemplate是否配置好了。(注:需要先启动本地的Redis服务端,Jedis客户端才能连接上

package com.scb.springbootdemo.config;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;

import static org.junit.Assert.*;

public class RedisConfigTest {
    public static void main(String[] args){
        ApplicationContext context=new AnnotationConfigApplicationContext(RedisConfig.class);
        RedisTemplate redisTemplate=context.getBean(RedisTemplate.class);
        redisTemplate.opsForValue().set("key1","value1");
        redisTemplate.opsForHash().put("hash","field","hashValue");
    }
}

程序日志如下:

       可以看到RedisConnection分别开启关闭了两次,分别用于执行 redisTemplate.opsForValue().set("key1","value1");

和redisTemplate.opsForHash().put("hash","field","hashValue"); 操作。

       接下来,我们在CMD中打开Redis客户端,输入命令查看是否已经存入值了。

五、配置RedisTemplate的序列化器

       从上图可以看到,Redis存入的并不是“key1”这样的字符串,这是怎么回事呢?首先需要清楚的是,Redis是一种基于字符串存储的NoSQL,而java是基于对象的语言,对象是无法存储到Redis中的,不过Java提供了序列化机制,只要类实现了java.io.Serializable接口,就代表类的对象能够进行序列化,通过将类对象进行序列化就能够得到二进制字符串。这样Redis就可以将这些类对象以字符串进行存储,java也可以将那些二进制字符串通过反序列化转化为对象。通过这个原理,Spring提供了序列化器的机制,并且实现了几个序列化器。

       对于序列化器,Spring提供了RedisSerializer接口,它有两个方法。一个是serialize,它能把那些可以序列化的对象转换为二进制字符串;另一个是deserialize,它能够通过反序列化把二进制字符串转换为Java对象。spring-data-redis主要提供了如下4种RedisSerializer接口的实现类:

  • JdkSerializationRedisSerializer:使用JDK提供的序列化功能。 优点是反序列化时不需要提供类型信息(class),但缺点是需要实现Serializable接口,还有序列化后的结果非常庞大,是JSON格式的5倍左右,这样就会消耗redis服务器的大量内存。(RedisTemplate默认使用此序列化器)
  • StringRedisSerializer:字符串编码,数据以string存储。(StringRedisTemplate默认使用此序列化器)
  • JacksonJsonRedisSerializer:使用Jackson库将对象序列化为JSON字符串。优点是速度快,序列化后的字符串短小精悍,不需要实现Serializable接口。但缺点也非常致命,那就是此类的构造函数中有一个类型参数,必须提供要序列化对象的类型信息(.class对象)。 通过查看源代码,发现其只在反序列化过程中用到了类型信息。
  • OxmSerializer:xml格式存储

而RedisTemplate中可供配置的序列化器属性,如下所示:

属性描述备注
defaultSerializer默认序列化器如果没有设置,则使用JdkSerializationRedisSerializer
keySerializerRedis键序列化器如果没有设置,则使用默认序列化器
valueSerializerRedis值序列化器如果没有设置,则使用默认序列化器
hashKeySerializerRedis散列结构field序列化器如果没有设置,则使用默认序列化器
hashValueSerializerRedis散列结构value序列化器如果没有设置,则使用默认序列化器
stringSerializer字符串序列化器RedisTemplate自动赋值为StringRedisSerializer对象

接下来,我们来配置RedisTemplate修改其默认的JdkSerializationRedisSerializer为StringRedisSerializer

    //配置RedisTemplate
    @Bean
    public RedisTemplate<Object,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
        RedisTemplate<Object,Object> redisTemplate=new RedisTemplate<>();
        //RedisTemplate会自动初始化StringRedisSerializer,所以这里直接获取
        RedisSerializer stringRedisSerializer=redisTemplate.getStringSerializer();
        //设置字符串序列化器,这样Spring就会把Redis的Key当作字符串处理
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        redisTemplate.setHashValueSerializer(stringRedisSerializer);
        //设置redisTemplate的连接工厂
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        return redisTemplate;
    }

通过上述配置,我们就成功将Redis的键和散列结构的field和value设置为StringRedisSerializer,这样把它们转换出来时就会是字符串了。

(注:可通过配置defaultSerializer属性为StringRedisSerializer,从而将keySerializer、valueSerializer、hashKeySerializer、hashValueSerializer一次性设置为StringRedisSerializer)

六、使用SessionCallback和RedisCallback接口

        在第四小节的程序日志中我们可以看到,RedisConnection分别开启关闭了两次用于执行操作。这样一条语句就开启关闭连接一次,明显是对资源的巨大浪费,那么有没有什么方法可以在一条连接中执行多个命令呢?

        为了克服这个问题,Spring为我们提供了SessionCallback和RedisCallback两个接口,他们的作用是让RedisTemplate进行回调,通过他们就可以在同一条连接下执行多个Redis命令。其中SessionCallback提供了良好的封装,对于开发者比较友好,因此在实际的开发中应该优先使用它;相对而言,RedisCallback接口比较底层,需要处理的内容也比较多,可读性较差,所以只有在需要修改那些较为底层规则时才使用它。如:序列化问题。

public class RedisConfigTest {
    public static void main(String[] args){
        ApplicationContext context=new AnnotationConfigApplicationContext(RedisConfig.class);
        RedisTemplate redisTemplate=context.getBean(RedisTemplate.class);
//        redisTemplate.opsForValue().set("key1","value1");
//        redisTemplate.opsForHash().put("hash","field","hashValue");
        useSessionCallback(redisTemplate);
    }
    public static void useSessionCallback(RedisTemplate redisTemplate){
        redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations redisOperations) throws DataAccessException {
                redisOperations.opsForValue().set("key2","value2");
                redisOperations.opsForHash().put("hash","field1","hashValue1");
                return null;
            }
        });
    }
}

 上述代码,我们采用了匿名类的方式去使用它。当然如果你的JDK是1.8及以上,你可以使用Lambda表达式去改写匿名类。

    public static void useSessionCallback(RedisTemplate redisTemplate){
        redisTemplate.execute((RedisOperations ro) -> {
            ro.opsForValue().set("key2","value2");
            ro.opsForHash().put("hash","field1","hashValue1");
            return null;
        });
    }

 运行结果如下:

 可以看到多个执行语句都在同一个连接下完成了。

七、总结

通过上述例子,我们已经大致学习了如何配置使用Redis了。下面,我们来仔细看看Redis所常用的五种数据结构:

结构类型结构存储的值功能操作
String可以是字符串、整数或者浮点数对整个字符串或者字符串的其中一部分执行操作;对象和浮点数执行自增(increment)或者自减(decrement)
List一个链表,链表上的每个节点都包含了一个字符串从链表的两端推入或者弹出元素;根据偏移量对链表进行修剪(trim);读取单个或者多个元素;根据值来查找或者移除元素
Set包含字符串的无序收集器(unorderedcollection),并且被包含的每个字符串都是独一无二的、各不相同添加、获取、移除单个元素;检查一个元素是否存在于某个集合中;计算交集、并集、差集;从集合里卖弄随机获取元素
Hash包含键值对的无序散列表添加、获取、移除单个键值对;获取所有键值对
Zset字符串成员(member)与浮点数分值(score)之间的有序映射,元素的排列顺序由分值的大小决定添加、获取、删除单个元素;根据分值范围(range)或者成员来获取元素

而Spring为了使用这五种数据类型,在RedisTemplate中定义了对5种数据结构操作:

  • redisTemplate.opsForValue();  //获取字符串操作接口

  • redisTemplate.opsForHash();   //获取hash操作接口

  • redisTemplate.opsForList();   //获取list操作接口

  • redisTemplate.opsForSet();    //获取set操作接口

  • redisTemplate.opsForZSet();   //获取有序set操作接口

这样就可以通过各类的操作接口来操作不同的数据类型了。

这篇文章主要讲解了在Spring中使用Redis的五种数据类型,而Redis还能作为事务、发布订阅等。见下一篇文章:

在Spring中使用Redis的高级功能(事务、消息队列、Lua脚本等)

 

 

 

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值