• 【Redis】Redis 的 Java 客户端(Jedis、SpringDataRedis)


    1. Jedis

    Jedis 是 Redis 官方推荐的 Java 连接开发工具。

    Jedis 的官网地址为:https://github.com/redis/jedis

    1.1 使用步骤

    1. 引入依赖:

      <dependency>
          <groupId>redis.clientsgroupId>
          <artifactId>jedisartifactId>
          <version>3.7.0version>
      dependency>
      
      • 1
      • 2
      • 3
      • 4
      • 5
    2. 创建 Jedis 对象,建立连接

      private Jedis jedis;
      
      // 1. 建立连接
      jedis = new Jedis("IP",6379);
      // 2. 设置密码
      jedis.auth("1234");
      // 3. 选择库(不选默认为 0 号库)
      jedis.select(0);
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    3. 使用 Jedis,方法名与 Redis 命令一致

      // 测试 String 类型
      // 存入数据
      String result = jedis.set("color", "red");
      System.out.println("result = " + result);
      // 获取数据
      String color = jedis.get("color");
      System.out.println(color);
      
      // 测试 hash 类型
      // 存入 hash 数据
      jedis.hset("user:1", "name", "jack");
      jedis.hset("user:1", "age", "21");
      // 取数据
      Map<String, String> map = jedis.hgetAll("user:1");
      map.forEach((k, v) ->{
          System.out.println(k + ": " + v);
      });
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
    4. 释放资源

      // 关闭资源
      if(jedis != null){
          jedis.close();
      }
      
      • 1
      • 2
      • 3
      • 4

    1.2 Jedis 连接池

    Jedis 本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,因此推荐使用 Jedis 连接池代替 Jedis 的直连方式。

    以下对 Jedis 做了一个封装:

    public class JedisConnectionFactory {
    
        private static final JedisPool jedisPool;
    
        static {
            // 配置连接池
            JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
            // 最大连接
            jedisPoolConfig.setMaxTotal(8);
            // 最大空闲连接
            jedisPoolConfig.setMaxIdle(8);
            // 最小空闲连接
            jedisPoolConfig.setMinIdle(0);
            // 设置最长等待时间(ms)
            jedisPoolConfig.setMaxWaitMillis(1000);
            // 创建连接池对象
            jedisPool = new JedisPool(jedisPoolConfig, "IP",
                    6379, 1000, "1234");
        }
    
        // 获取 Jedis 对象
        public static Jedis getJedis(){
            return jedisPool.getResource();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    2. SpringDataRedis

    2.1 基本介绍

    SpringData 是 Spring 中数据操作的模块,包含对各种数据库的集成,其中对 Redis 的集成模块就叫做 SpringDataRedis,官网地址为:https://spring.io/projects/spring-data-redis

    SpringDataRedis 有很强大的功能:

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

    2.1 使用方式

    SpringDataRedis 中提供了 RedisTemplate 工具类,其中封装了各种对 Redis 的操作。并且将不同数据类型的操作 API 封装到了不同的类型中:

    API返回值类型说明
    redisTemplate.opsForValue()ValueOperations操作 String 类型数据
    redisTemplate.opsForHash()HashOperations操作 Hash 类型数据
    redisTemplate.opsForList()ListOperations操作 List 类型数据
    redisTemplate.opsForSet()SetOperations操作 Set 类型数据
    redisTemplate.opsForZSet()ZSetOperations操作 SortedSet 类型数据
    redisTemplate通用命令

    SpringBoot 已经提供了对 SpringDataRedis 的支持,使用方式如下:

    1. 引入依赖

      
      <dependency>
          <groupId>org.springframework.bootgroupId>
          <artifactId>spring-boot-starter-data-redisartifactId>
      dependency>
      
      
      <dependency>
          <groupId>org.apache.commonsgroupId>
          <artifactId>commons-pool2artifactId>
      dependency>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
    2. 配置文件(Spring 默认使用 lettuce 实现,可以直接引用,如果要选择 jedis,则要额外引入相关依赖)

      spring:
        redis:
          host: IP
          port: 6379
          password: 1234
          database: 0 # 选择0号数据库
          lettuce: # 选择 lettuce
            pool:
              max-active: 8 # 最大连接
              max-idle: 8 # 最大空闲连接
              min-idle: 0 # 最小空闲连接
              max-wait: 1000 # 连接等待时间
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
    3. 注入 RedisTemplate

      @Autowired
      private RedisTemplate redisTemplate;
      
      • 1
      • 2
    4. 编写测试

      @Autowired
      private RedisTemplate redisTemplate;
      
      // 写入一条 String 数据
      redisTemplate.opsForValue().set("name", "rose");
      // 获取数据
      Object name = redisTemplate.opsForValue().get("name");
      System.out.println("name = " + name);
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

    2.3 SpringDataRedis 的序列化方式

    RedisTemplate 可以接收任意 Object 作为值写入 Redis,只不过写入前会把 Object 序列化为字节形式,默认是采用 JDK 序列化,得到的结果为:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-daFb0o9V-1660125804789)(C:/Users/bbbbbge/Pictures/接单/1660122313198.png)]

    在 RedisTemplate 的源码中,我们可以发现 key 和 value 的序列化器的值为 null。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zQqql4eb-1660125804790)(C:/Users/bbbbbge/Pictures/接单/1660122592029.png)]

    当默认的序列化器的值为 null 时,就会通过 JDK 的序列化器来对 key 和 value 进行序列化。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WdXDKHkE-1660125804790)(C:/Users/bbbbbge/Pictures/接单/1660122709016.png)]

    而 JDK 的序列化器是通过 ObjectOutputStream 将 key 和 value 转化成字节再传递到 Redis 中的。因此会具有如下缺点:

    • 可读性差
    • 内存占用大

    解决办法:

    改变 RedisTemplate 的序列化方式,而 RedisTemplate 中除了可以使用 JdkSerializationRedisSerializer 外,还能够使用以下两种:

    • StringRedisSerializer:用于将 String 进行序列化的工具,适合当作 key 的序列化器。
    • GenericToStringSerializer(不推荐,原因在下一节):是转 JSON 字符串的序列化工具,适合用作含有对象的 value 进行进行序列化。

    自定义 RedisTemplate 的序列化方式如下:

    @Configuration
    public class RedisConfig {
    
        @Bean
        public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory){
            // 创建 RedisTemplate 对象
            RedisTemplate<String, Object> template = new RedisTemplate<>();
            // 设置连接工厂
            template.setConnectionFactory(connectionFactory);
            // 创建 JSON 序列化工具
            GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
            // 设置 Key 的序列化
            template.setKeySerializer(RedisSerializer.string());
            template.setHashKeySerializer(RedisSerializer.string());
            // 设置 Value 的序列化
            template.setValueSerializer(jsonRedisSerializer);
            template.setHashValueSerializer(jsonRedisSerializer);
            // 返回
            return template;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    注意:

    使用 GenericToStringSerializer 需要引入 json 依赖(mvc 依赖中会自带):

            <dependency>
                <groupId>com.fasterxml.jackson.coregroupId>
                <artifactId>jackson-databindartifactId>
            dependency>
    
    • 1
    • 2
    • 3
    • 4

    2.4 StringRedisTemplate

    尽管 JSON 的序列化方式可以满足我们的需求,但依然存在一些问题,如图:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TYKsZxhl-1660125804791)(C:/Users/bbbbbge/Pictures/接单/1660124103339.png)]

    为了在反序列化时知道对象的类型,JSON 序列化器会将类的 class 类型写入 json 结果中,再存入 Redis,会带来额外的内存开销。

    解决办法:

    为了节省内存空间,其实并不会使用 JSON 序列化器来处理 value,而是使用 String 序列化器,要求只能才能出 String 类型的 key 和 value。当我们需要存储 Java 对象时,手动完成对象序列化和反序列化。

    Spring 默认提供了一个 StringRedisTemplate 类,它的 key 和 value 的序列化方式默认是 String 方式,省去了自定义 RedisTemplate 的过程。

    使用方式如下:

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    // JSON 工具
    private static final ObjectMapper objectMapper = new ObjectMapper();
    
    
    // 准备对象
    User user = new User("李四", 18);
    // 手动序列化
    String jsonString = objectMapper.writeValueAsString(user);
    // 写入数据到 redis
    stringRedisTemplate.opsForValue().set("user:9", jsonString);
    // 读取数据
    String val = stringRedisTemplate.opsForValue().get("user:9");
    // 反序列化
    User user1 = objectMapper.readValue(val, User.class);
    System.out.println("user1 = " + user1);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
  • 相关阅读:
    狂刷《Java权威面试指南(阿里版)》,冲击“金九银十”有望了
    23、Mybatis查询功能4(查询结果为一个map集合(多条数据))
    基于4G/5G协同的高密重载场景网络规划方法
    PaddleOCR ‘could not create a primitive descriptor for a reorder primitive‘异常处理
    人工智能AI界的龙头企业,炸裂的“英伟达”时代能走多远
    秒懂算法 | 数论算法实例分析之阿里巴巴的宝藏与欧拉函数例题
    Java实现图片保存到pdf的某个位置2
    vue3 的 ref、isRef、toRef、toRefs、toRaw 详细介绍
    Android11适配
    接口性能测试方案
  • 原文地址:https://blog.csdn.net/weixin_51367845/article/details/126271732