Redis客户端Jedis和SpringDataRedis使用操作详解与释义

前提提要

🏓Redis有多种客户端操作方法,本博文主要介绍两种常用的操作方法。使用jedis来操作客户端。并且考虑到spring的流行程度,所以也对SpringDataRedis操作的方式进行了详细的说明。

具体的说明看博文🤨

一,操作客户端总览

在上两篇博文的学习中,我们知道官网给了我们很多的信息。通过在Redis官方网站有各种操作redis客户端的说明:
在这里插入图片描述
我们只看JAVA是如何通过简单又轻便的方式来操作redis的。🍩
在这里插入图片描述
并且,对于jedislettuceSpring Data Redis所支持的两种操作方式,并且lettucespring data中被作为是默认的操作方式

二,Jedis操作方式

🚞对于Jedis的操作方式,我们先来快速的入个门,Jedis的 官网地址https://github.com/redis/jedis,按照管方所给的信息来一步步的搭建。

对于Jedis操作方式的有点之一就是jedis的各种API非常的贴近于我们上篇博文所介绍的各种命令。
在这里插入图片描述
JedisRedis命令作为方法命令的方式,体现了简单易用,学习成本低。🌆但是,有缺点是Jedis实例是线程不安全的。如果是多线程环境下,需要基于连接池的方式来使用。我们先来看看朴素的方式,也就是没有考虑线程安全性的方式如何操作Redis

2.1 朴素Jedis操作方式

博主是通过单元测试的方式来验证的。步骤如下:

1.引入依赖

  <!--jedis-->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>4.1.1</version>
        </dependency>
        <!--junit-->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.7.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-nop</artifactId>
            <version>1.7.2</version>
        </dependency>

2.建立对应的连接,

public class JedisTest {
    private Jedis jedis;
    @BeforeEach
    void setup(){
//        1.建立连接
        jedis = new Jedis("192.168.81.150", 6379);
//          2. 设置密码
        jedis.auth("123321");
//        选用库
        jedis.select(0);
    }
    // 关闭连接
    @AfterEach
    void teardown(){
        if(jedis != null) jedis.close();
    }
}

3.Jedis测试简单示例

  @Test
    void testString(){
//        存入数据
        String result = jedis.set("name", "fangshaolei");
        System.out.println("result = " + result);
//        获取数据
        String name = jedis.get("name");
        System.out.println("name = " + name);
    }

    @Test
    void testHash(){
        jedis.hset("user:1", "name", "fangshaolei");
        jedis.hset("user:1", "age", "21");
        //获取
        Map<String, String> map = jedis.hgetAll("user:1");
        System.out.println(map);

    }

4. 结果展示

在这里插入图片描述
结果测试成功,jedis原始操作方式。

5.总结

Jedis使用的基本步骤:

  • 引入依赖
  • 创建Jedis对象,建立连接
  • 使用Jedis,方法名与上篇博文Redis命令一致
  • 释放资源

2.2 Jedis连接池操作方式

🌾我们知道,Jedis本身是线程不安全的,并且频繁的建立和销毁连接会有性能的损耗,对于官方也推荐我们使用Jedis连接池来代替上述方法中朴素Jedis的直连方式。
其实连接池的操作和上述的步骤基本一致。获取Jedis对象的方式由原来的创建,变成了从连接池中获取。

按照程序设计的思想,把连接池的获取操作创建为工具类。如下:

public class JedisConnectionFactory {
    private static final JedisPool jedisPool;
    static{
//                配置连接池
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(8);
        config.setMaxIdle(8);
        config.setMinIdle(0);
        config.setMaxWaitMillis(1000);
        jedisPool = new JedisPool(config,
                "192.168.81.150",6379 , 1000,"123321" );
         // 配置连接池的参数要切换
    }
    public static Jedis getJedis(){
        return jedisPool.getResource();
    }
}

而对于使用,只需要把上述朴素Jedis操作的方式改为从连接池中获取即可。

    private Jedis jedis;
    @BeforeEach
    void setup(){
//        1.建立连接
//        jedis = new Jedis("192.168.81.150", 6379);
        jedis = JedisConnectionFactory.getJedis();
//          2. 设置密码
        jedis.auth("123321");
//        选用库
        jedis.select(0);
    }

总结

JedisPool使用的基本步骤:

  • 引入依赖
  • 创建连接池,设置连接池参数。
  • 从连接池中获取Jedis对象,建立连接
  • 使用Jedis,方法名与上篇博文Redis命令一致
  • 释放资源

三. 基于SpringBoot整合Jedis(SpringDataRedis)

SpringBoot已经成为企业开发的标配,所以,在学习Java新技术的时候,我们都要考虑一下,能不能基于SpringBoot来整合下Jedis的连接池呢?

3.1 SpringDataRedis基本使用

SpringDataSpring中数据操作的模块,包含对各种数据库的集成,其中对Redis的集成模块就叫做SpringDataRedis,👩‍⚖️官网地址https://spring.io/projects/spring-data-redis,对于SpringDataRedis的功能官网也进行了详细的说明,主要有以下几点:

  • 提供了对不同Redis客户端的整合(Lettuce(默认)和Jedis
  • 提供了RedisTemplate统一API来操作Redis
  • 支持Redis的发布订阅模型
  • 支持Redis哨兵和Redis集群
  • 支持基于Lettuce的响应式编程
  • 支持基于JDKJSON字符串Spring对象的数据序列化及反序列化
  • 支持基于RedisJDKCollection实现

对于以后的博文如果设计到项目部分,都是基于springboot来进行展示和说明。

在这里插入图片描述

对于各个版本的支持

其中,对于SpringDataRedis提供了RedisTemplate工具类,其中封装了各种对Redis的操作。

但是,SpringDataRedis不在像Jedis一样,各个命令作为方法名。而是有点类似于官方查阅文档的形式,将不同数据类型的操作API封装到了不同的类型中:
在这里插入图片描述
和朴素Jedis操作类似,直接先开始快速入门:
SpringBoot已经提供了对SpringDataRedis的支持,使用非常简单:

1. 导入依赖

在建立SpringBoot项目的时候,在NoSQL勾选上redis,但是,由于SpingBoot默认支持连接池的方式连接,所以,还要加上一个连接池依赖。

 <!--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>

2. 配置相关连接信息

🚃在配置文件中配置连接redis的一些必要信息。

这里我直接使用lettuce客户端的方式操作,如果是redis还需要配置一些额外信息。

spring:
  redis:
    host: 192.168.81.150
    port: 6379
    password: 123321
    lettuce:
      pool:
        max-wait: 100
        min-idle: 8
        max-idle: 8
        max-active: 8

3. 注入RedisTemplate

   @Autowired
    private RedisTemplate redisTemplate;

4. 编写测试代码

   @Test
    void contextLoads() {
        redisTemplate.opsForValue().set("username", "fangshaolei");
//        获取名字
        Object username = redisTemplate.opsForValue().get("username");
        System.out.println("username = " + username);
    }

总结

SpringDataRedis的使用步骤:

  • 引入spring-boot-starter-data-redis依赖
  • application.yml配置Redis信息
  • 注入RedisTemplate

3.2 SpringDataRedis的两种序列方案

RedisTemplate可以接收任意Object作为值写入Redis,只不过写入前会把Object序列化为字节形式,默认是采用JDK序列化,得到的结果是这样的:
在这里插入图片描述
缺点也暴露的很明显:

  • 可读性查
  • 内存占用的较大

1. 通过自定义序列化方式

但是,在SpringBoot中给我们支持了强大的组件定制服务。我们可以自定义RedisTemplate的序列化方式,代码如下:

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
//      创建redistemplate对象
        RedisTemplate redisTemplate = new RedisTemplate();
//        设置连接工厂
        redisTemplate.setConnectionFactory(redisConnectionFactory);
//        设置序列化工具
        GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
//        key hashkey采用string的方式序列化
        redisTemplate.setKeySerializer(RedisSerializer.string());
        redisTemplate.setHashKeySerializer(RedisSerializer.json());
//        value hashvalue采用json序列化
        redisTemplate.setValueSerializer(jsonRedisSerializer);
        redisTemplate.setHashValueSerializer(jsonRedisSerializer);

        return  redisTemplate;
    }
}

我们在通过一个方法来进行测试,测试代码如下:

  @Test
    void testObject(){
        redisTemplate.opsForValue().set("user:1", new User("fangshaolei", 21));
//
        User o = (User) redisTemplate.opsForValue().get("user:1");
        System.out.println("o = " + o);
    }

🆘注意: 这里可能会报错,找不到Jackson依赖,本来SpringMVC自动集成了Jackson依赖,所以我们这里手动导入依赖:

  <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>

👨‍🏫发现,在redis中的数据已经通过我们自定义的序列化方式有所改变:
在这里插入图片描述

2. StringRedisTemplate 方式操作

已经达到了我们的目的,但是尽管JSON的序列化方式可以满足我们的需求,但仍然存在一些问题,如图所示:
在这里插入图片描述
由于SpringDataRedis自动的给我们进行序列化和反序列化,为了操作的需要,在反序列化中知道对象的类型。所以,JSON序列化容器会将类的CLASS类型写入到JSON结果中,存入Redis,会带来额外的内存开销。

🎸那我们如何保证能够节省内存(即将@class字段去除),又能保证反序列化成功呢?

唯一的方法,就是序列化和反序列化的操作,交给我们自己来做,我们也不必去配置反序列化方式。

也就是我们为了节省内存空间,我们**并不会使用JSON序列化器来处理value,**而是统一使用String序列化器,要求只能存储String类型key和value。当需要存储Java对象时,手动完成对象的序列化和反序列化
在这里插入图片描述
🥗Spring默认提供了一个StringRedisTemplate类,它的keyvalue的序列化方式默认就是String方式。省去了我们自定义RedisTemplate的过程:

在代码中,我使用了private static final ObjectMapper mapper = new ObjectMapper();的序列化工具来进行序列化。读者可以自行选择序列化工具。

@SpringBootTest
class StringTemplateTest {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Test
    void contextLoads() {
        stringRedisTemplate.opsForValue().set("username", "son of sun");
//        获取名字
        Object username = stringRedisTemplate.opsForValue().get("username");
        System.out.println("username = " + username);
    }

    private static final ObjectMapper mapper = new ObjectMapper();
    @Test
    void testObject() throws JsonProcessingException {
        User user = new User("fangshaolei", 21);
//        手动序列化
        String json = mapper.writeValueAsString(user);
//        写入数据
        stringRedisTemplate.opsForValue().set("user:100",json );
//        获取数据
        String jsonUser = stringRedisTemplate.opsForValue().get("user:100");
//        手动反序列化
        User user1 = mapper.readValue(jsonUser, User.class);
        System.out.println("user1 = " + user1);
    }

    @Test
    public void testHash(){
        stringRedisTemplate.opsForHash().put("user:101", "name", "fangshaolei");
        stringRedisTemplate.opsForHash().put("user:101", "age", 12);

        Map<Object, Object> entries = stringRedisTemplate.opsForHash().entries("user:101");
        System.out.println("entries = " + entries);
    }
}

最后的效果如下:
在这里插入图片描述

3. RedisTemplate的两种序列化实践方案总结

按照上述所介绍的,对两种方案进行总结。

方案一:
  • 自定义RedisTemplate
  • 修改RedisTemplate的序列化器为GenericJackson2JsonRedisSerializer
方案二:
  • 使用StringRedisTemplate
  • 写入Redis时,手动把对象序列化为JSON
  • 读取Redis时,手动把读取到的JSON反序列化为对象

对于博主,🎭我推荐使用方案二作为springboot操作redis的方式。优点有很多。

四,总结

🚞本博文对jedis的操作和SpringDataRedis的操作都进行了详细的解释和演示,并对在springboot整合redis的方式中说明了两种序列化方案。

其中第二种方案是开发中所推荐的方案,至此我们已经学会了开发中的关键一步————SpringBoot整合redis,后续可能会有小demo来演示,强化理解。


🥗🥗🥗文章还有许多不足之处,欢迎指正。

【参考博文】
https://blog.csdn.net/qq_36781505/article/details/86612988

https://www.cnblogs.com/zeng1994/p/03303c805731afc9aa9c60dbbd32a323.html

https://www.jianshu.com/p/a1038eed6d44

https://www.cnblogs.com/liuling/p/2014-4-19-04.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值