Bootstrap

后端开发 Springboot整合Redis Spring Data Redis 模板

目录

redis 配置 RedisConfig 类

完整代码

代码讲解

1. 类定义和注解

2. 定义 RedisTemplate Bean

3. 配置 JSON 序列化

4. 配置 Redis 的 key 和 value 序列化方式

5. 完成配置并返回 RedisTemplate

总结

redis 服务接口实现类

类级别

注入 RedisTemplate

常用 Redis 操作

1. 设置和获取过期时间

2. 获取 Redis 键

3. 操作字符串类型数据

4. 操作哈希类型数据

5. 操作列表类型数据

6. 操作集合类型数据

7. 操作有序集合类型数据

其他方法

总结

Redis 模板注释版本


redis 配置 RedisConfig 类

完整代码

package com.ican.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
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.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * Redis配置
 *
 * @author Dduo
 * @date 2024/12/02 15:40
 **/
@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        // Json序列化配置
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
                ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        // String序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // 使用String来序列化和反序列化key
        template.setKeySerializer(stringRedisSerializer);
        // 使用Jackson来序列化和反序列化value
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // Hash的key采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // Hash的value采用Jackson的序列化方式
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }

}

代码讲解

1. 类定义和注解
java


复制代码
@Configuration
public class RedisConfig {
  • @Configuration 注解表示这是一个配置类,它会被 Spring 容器自动扫描并注册为一个 Bean。
2. 定义 RedisTemplate Bean
java


复制代码
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
    RedisTemplate<String, Object> template = new RedisTemplate<>();
    template.setConnectionFactory(redisConnectionFactory);
  • @Bean 注解告诉 Spring 这是一个需要管理的 Bean。方法 redisTemplate 创建并配置一个 RedisTemplate,该模板用于在 Redis 中执行操作。
  • RedisConnectionFactory 是 Redis 连接的工厂,Spring Data Redis 使用它来创建与 Redis 服务器的连接。
3. 配置 JSON 序列化
java


复制代码
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
        ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
  • 这里使用了 Jackson2JsonRedisSerializer 来配置 Redis 中存储的数据的序列化方式,将对象转为 JSON 格式进行存储。
  • ObjectMapper 是 Jackson 提供的类,用于将 Java 对象转为 JSON。
  • setVisibility 方法设置哪些 Java 类的字段应该被序列化,JsonAutoDetect.Visibility.ANY 表示包括所有字段(私有、保护和公共字段都包括)。
  • activateDefaultTyping 方法指定序列化输入的类型,NON_FINAL 表示可以序列化非 final 修饰的类型(例如 String、Integer 是 final 的,无法序列化)。
  • JsonTypeInfo.As.PROPERTY 指定类型信息应该作为 JSON 属性存储在序列化对象中。
4. 配置 Redis 的 key 和 value 序列化方式
java


复制代码
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
template.setKeySerializer(stringRedisSerializer);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashKeySerializer(stringRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
  • StringRedisSerializer 用来将 Redis 的键(key)序列化成字符串格式。
  • jackson2JsonRedisSerializer 用于将 Redis 的值(value)序列化为 JSON 格式。
  • 这里也配置了 Redis 的哈希表(hash)数据类型,指定哈希的键和值的序列化方式。
5. 完成配置并返回 RedisTemplate
java


复制代码
template.afterPropertiesSet();
return template;
  • afterPropertiesSet 方法是 RedisTemplate 的初始化方法,用来确认所有的属性都已经设置完成。
  • 最后返回配置好的 RedisTemplate 实例。

总结

这段代码完成了如下几项工作:

  • 配置 RedisTemplate 连接工厂,以便与 Redis 进行通信。
  • 配置了 JSON 序列化和反序列化机制,使得 Redis 中的值使用 JSON 格式存储。
  • 配置了 Redis 键(key)使用字符串序列化,值(value)使用 Jackson 序列化。
  • 配置了 Redis 哈希表的键和值的序列化方式。

通过这些配置,可以让应用程序与 Redis 进行无缝的数据存取操作,且数据在存储到 Redis 时被序列化为 JSON 格式,使得存取更加灵活和易于处理。

redis 服务接口实现类

package com.ican.service;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * Redis服务接口实现类
 *
 * @author Dduo
 */
@Service
@SuppressWarnings("all")
public class RedisService {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;


    public Boolean setExpire(String key, long timeout, TimeUnit timeUnit) {
        return redisTemplate.expire(key, timeout, timeUnit);
    }


    public Long getExpire(String key, TimeUnit timeUnit) {
        return redisTemplate.getExpire(key, timeUnit);
    }

    public Collection<String> getKeys(String pattern) {
        return redisTemplate.keys(pattern);
    }

    public Boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    public <T> void setObject(String key, T value) {
        redisTemplate.opsForValue().set(key, value);
    }

    public <T> void setObject(String key, T value, long timeout, TimeUnit timeUnit) {
        redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
    }


    public <T> T getObject(String key) {
        return (T) redisTemplate.opsForValue().get(key);
    }


    public Boolean deleteObject(String key) {
        return redisTemplate.delete(key);
    }


    public Long deleteObject(List<String> keys) {
        return redisTemplate.delete(keys);
    }


    public Long incr(String key, long delta) {
        return redisTemplate.opsForValue().increment(key, delta);
    }


    public Long decr(String key, long delta) {
        return redisTemplate.opsForValue().decrement(key, -delta);
    }


    public <T> void setHash(String key, String hashKey, T value) {
        redisTemplate.opsForHash().put(key, hashKey, value);
    }


    public <T> Boolean setHash(String key, String hashKey, T value, long timeout, TimeUnit timeUnit) {
        redisTemplate.opsForHash().put(key, hashKey, value);
        return setExpire(key, timeout, timeUnit);
    }


    public <T> void setHashAll(String key, Map<String, T> map) {
        redisTemplate.opsForHash().putAll(key, map);
    }


    public <T> Boolean setHashAll(String key, Map<String, T> map, long timeout, TimeUnit timeUnit) {
        redisTemplate.opsForHash().putAll(key, map);
        return setExpire(key, timeout, timeUnit);
    }


    public <T> T getHash(String key, String hashKey) {
        return (T) redisTemplate.opsForHash().get(key, hashKey);
    }


    public Map getHashAll(String key) {
        return redisTemplate.opsForHash().entries(key);
    }


    public <T> void deleteHash(String key, T... hashKeys) {
        redisTemplate.opsForHash().delete(key, hashKeys);
    }


    public Boolean hasHashValue(String key, String hashKey) {
        return redisTemplate.opsForHash().hasKey(key, hashKey);
    }


    public Long incrHash(String key, String hashKey, Long delta) {
        return redisTemplate.opsForHash().increment(key, hashKey, delta);
    }


    public Long decrHash(String key, String hashKey, Long delta) {
        return redisTemplate.opsForHash().increment(key, hashKey, -delta);
    }


    public <T> Long setList(String key, T value) {
        return redisTemplate.opsForList().rightPush(key, value);
    }


    public <T> Long setList(String key, T value, long timeout, TimeUnit timeUnit) {
        Long count = redisTemplate.opsForList().rightPush(key, value);
        setExpire(key, timeout, timeUnit);
        return count;
    }


    public <T> Long setListAll(String key, T... values) {
        return redisTemplate.opsForList().rightPushAll(key, values);
    }


    public <T> Long setListAll(String key, long timeout, TimeUnit timeUnit, T... values) {
        Long count = redisTemplate.opsForList().rightPushAll(key, values);
        setExpire(key, timeout, timeUnit);
        return count;
    }


    public <T> List<T> getList(String key, long start, long end) {
        List<T> result = (List<T>) redisTemplate.opsForList().range(key, start, end);
        return result;
    }


    public <T> T getListByIndex(String key, long index) {
        return (T) redisTemplate.opsForList().index(key, index);
    }


    public Long getListSize(String key) {
        return redisTemplate.opsForList().size(key);
    }


    public <T> Long deleteList(String key, long count, T value) {
        return redisTemplate.opsForList().remove(key, count, value);
    }


    public <T> Long setSet(String key, T... values) {
        return redisTemplate.opsForSet().add(key, values);
    }


    public <T> Long setSet(String key, long timeout, TimeUnit timeUnit, T... values) {
        Long count = redisTemplate.opsForSet().add(key, values);
        setExpire(key, timeout, timeUnit);
        return count;
    }


    public <T> Set<T> getSet(String key) {
        Set<T> result = (Set<T>) redisTemplate.opsForSet().members(key);
        return result;
    }


    public <T> Long deleteSet(String key, T... values) {
        return redisTemplate.opsForSet().remove(key, values);
    }


    public <T> Boolean hasSetValue(String key, T value) {
        return redisTemplate.opsForSet().isMember(key, value);
    }


    public Long getSetSize(String key) {
        return redisTemplate.opsForSet().size(key);
    }


    public <T> Double incrZet(String key, T value, Double score) {
        return redisTemplate.opsForZSet().incrementScore(key, value, score);
    }


    public <T> Double decrZet(String key, T value, Double score) {
        return redisTemplate.opsForZSet().incrementScore(key, value, -score);
    }


    public <T> Long deleteZetScore(String key, T... values) {
        return redisTemplate.opsForZSet().remove(key, values);
    }


    public Map<Object, Double> zReverseRangeWithScore(String key, long start, long end) {
        return redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end)
                .stream()
                .collect(Collectors.toMap(ZSetOperations.TypedTuple::getValue, ZSetOperations.TypedTuple::getScore));
    }


    public <T> Double getZsetScore(String key, T value) {
        return redisTemplate.opsForZSet().score(key, value);
    }


    public Map<Object, Double> getZsetAllScore(String key) {
        return Objects.requireNonNull(redisTemplate.opsForZSet().rangeWithScores(key, 0, -1))
                .stream()
                .collect(Collectors.toMap(ZSetOperations.TypedTuple::getValue, ZSetOperations.TypedTuple::getScore));
    }


}

这段代码实现了一个 RedisService 类,提供了与 Redis 数据库交互的多种方法,涵盖了对 Redis 的常见操作,包括字符串、哈希、列表、集合、有序集合等数据类型的增删改查功能,并支持设置过期时间。以下是该类各部分的详细讲解:

类级别

java


复制代码
@Service
@SuppressWarnings("all")
public class RedisService {
  • @Service 注解表示这是一个 Spring 服务类,Spring 会将其注册为一个 Bean 进行管理,供应用程序其他部分使用。
  • @SuppressWarnings("all") 用来抑制编译器的警告,通常是为了避免不必要的警告信息。

注入 RedisTemplate

java


复制代码
@Resource
private RedisTemplate<String, Object> redisTemplate;
  • @Resource 注解表示自动注入 RedisTemplate,这是 Spring Data Redis 提供的用于操作 Redis 的模板类。通过它可以执行 Redis 操作。
  • RedisTemplate<String, Object> 表示 Redis 键的类型为 String,值的类型为 Object,这允许操作 Redis 中的多种数据类型。

常用 Redis 操作

1. 设置和获取过期时间
java


复制代码
public Boolean setExpire(String key, long timeout, TimeUnit timeUnit) {
    return redisTemplate.expire(key, timeout, timeUnit);
}

public Long getExpire(String key, TimeUnit timeUnit) {
    return redisTemplate.getExpire(key, timeUnit);
}
  • setExpire 设置 Redis 键的过期时间。
  • getExpire 获取 Redis 键的剩余过期时间。
2. 获取 Redis 键
java


复制代码
public Collection<String> getKeys(String pattern) {
    return redisTemplate.keys(pattern);
}

public Boolean hasKey(String key) {
    return redisTemplate.hasKey(key);
}
  • getKeys 获取符合给定模式的所有键。
  • hasKey 检查 Redis 中是否存在指定的键。
3. 操作字符串类型数据
java


复制代码
public <T> void setObject(String key, T value) {
    redisTemplate.opsForValue().set(key, value);
}

public <T> T getObject(String key) {
    return (T) redisTemplate.opsForValue().get(key);
}

public Long incr(String key, long delta) {
    return redisTemplate.opsForValue().increment(key, delta);
}

public Long decr(String key, long delta) {
    return redisTemplate.opsForValue().decrement(key, -delta);
}
  • setObjectgetObject 分别用于设置和获取 Redis 中的字符串类型数据。
  • incrdecr 用于对字符串类型的值进行递增和递减操作。
4. 操作哈希类型数据
java


复制代码
public <T> void setHash(String key, String hashKey, T value) {
    redisTemplate.opsForHash().put(key, hashKey, value);
}

public <T> T getHash(String key, String hashKey) {
    return (T) redisTemplate.opsForHash().get(key, hashKey);
}

public Map getHashAll(String key) {
    return redisTemplate.opsForHash().entries(key);
}
  • setHashgetHash 用于设置和获取 Redis 中哈希类型的数据。
  • getHashAll 获取哈希表的所有键值对。
5. 操作列表类型数据
java


复制代码
public <T> Long setList(String key, T value) {
    return redisTemplate.opsForList().rightPush(key, value);
}

public <T> List<T> getList(String key, long start, long end) {
    List<T> result = (List<T>) redisTemplate.opsForList().range(key, start, end);
    return result;
}
  • setList 用于将元素添加到 Redis 列表的末尾。
  • getList 用于获取列表中的指定范围的元素。
6. 操作集合类型数据
java


复制代码
public <T> Long setSet(String key, T... values) {
    return redisTemplate.opsForSet().add(key, values);
}

public <T> Set<T> getSet(String key) {
    Set<T> result = (Set<T>) redisTemplate.opsForSet().members(key);
    return result;
}
  • setSet 用于将元素添加到 Redis 集合。
  • getSet 用于获取 Redis 集合中的所有元素。
7. 操作有序集合类型数据
java


复制代码
public <T> Double incrZet(String key, T value, Double score) {
    return redisTemplate.opsForZSet().incrementScore(key, value, score);
}

public Map<Object, Double> zReverseRangeWithScore(String key, long start, long end) {
    return redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end)
            .stream()
            .collect(Collectors.toMap(ZSetOperations.TypedTuple::getValue, ZSetOperations.TypedTuple::getScore));
}
  • incrZet 用于增减有序集合元素的分数。
  • zReverseRangeWithScore 获取有序集合中的指定范围的元素和对应的分数,并以 Map 返回。

其他方法

  • deleteObjectdeleteList 等方法用于删除 Redis 中的键值对、列表中的元素等。
  • hasHashValue 用于检查 Redis 哈希表中是否存在指定的值。
  • deleteSetdeleteZetScore 用于删除集合和有序集合中的元素。

总结

RedisService 类封装了多种与 Redis 交互的常用方法,包括对不同数据类型的操作(字符串、哈希、列表、集合、有序集合等)。这些方法提供了简洁的接口,使得应用程序可以方便地使用 Redis 作为缓存和数据存储系统。并且,部分方法支持设置过期时间,使得存储的数据可以自动失效。

Redis 模板注释版本

package com.ican.service;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * Redis服务接口实现类
 *
 * @author Dduo
 */
@Service
@SuppressWarnings("all")
public class RedisService {

    // 注入 RedisTemplate
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 设置 Redis 键的过期时间
     *
     * @param key       Redis 键
     * @param timeout   过期时间
     * @param timeUnit  时间单位
     * @return 是否成功设置过期时间
     */
    public Boolean setExpire(String key, long timeout, TimeUnit timeUnit) {
        return redisTemplate.expire(key, timeout, timeUnit);
    }

    /**
     * 获取 Redis 键的剩余过期时间
     *
     * @param key       Redis 键
     * @param timeUnit  时间单位
     * @return 剩余过期时间(单位为 timeUnit)
     */
    public Long getExpire(String key, TimeUnit timeUnit) {
        return redisTemplate.getExpire(key, timeUnit);
    }

    /**
     * 获取符合给定模式的所有 Redis 键
     *
     * @param pattern 键的模式(可以使用通配符)
     * @return 键的集合
     */
    public Collection<String> getKeys(String pattern) {
        return redisTemplate.keys(pattern);
    }

    /**
     * 检查 Redis 中是否存在指定的键
     *
     * @param key Redis 键
     * @return 是否存在该键
     */
    public Boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 设置 Redis 中的字符串类型数据
     *
     * @param key   Redis 键
     * @param value 存储的值
     * @param <T>   值的类型
     */
    public <T> void setObject(String key, T value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 设置 Redis 中的字符串类型数据,并设置过期时间
     *
     * @param key       Redis 键
     * @param value     存储的值
     * @param timeout   过期时间
     * @param timeUnit  时间单位
     * @param <T>       值的类型
     */
    public <T> void setObject(String key, T value, long timeout, TimeUnit timeUnit) {
        redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
    }

    /**
     * 获取 Redis 中的字符串类型数据
     *
     * @param key Redis 键
     * @param <T> 值的类型
     * @return Redis 存储的值
     */
    public <T> T getObject(String key) {
        return (T) redisTemplate.opsForValue().get(key);
    }

    /**
     * 删除 Redis 中的字符串类型数据
     *
     * @param key Redis 键
     * @return 删除成功返回 true,否则返回 false
     */
    public Boolean deleteObject(String key) {
        return redisTemplate.delete(key);
    }

    /**
     * 删除 Redis 中的字符串类型数据(支持批量删除)
     *
     * @param keys Redis 键的集合
     * @return 被删除的键的数量
     */
    public Long deleteObject(List<String> keys) {
        return redisTemplate.delete(keys);
    }

    /**
     * 对 Redis 中的字符串类型值进行递增操作
     *
     * @param key   Redis 键
     * @param delta 增加的值
     * @return 增加后的值
     */
    public Long incr(String key, long delta) {
        return redisTemplate.opsForValue().increment(key, delta);
    }

    /**
     * 对 Redis 中的字符串类型值进行递减操作
     *
     * @param key   Redis 键
     * @param delta 减少的值
     * @return 减少后的值
     */
    public Long decr(String key, long delta) {
        return redisTemplate.opsForValue().decrement(key, -delta);
    }

    /**
     * 设置 Redis 中哈希类型的数据
     *
     * @param key     Redis 键
     * @param hashKey 哈希键
     * @param value   存储的值
     * @param <T>     值的类型
     */
    public <T> void setHash(String key, String hashKey, T value) {
        redisTemplate.opsForHash().put(key, hashKey, value);
    }

    /**
     * 设置 Redis 中哈希类型的数据,并设置过期时间
     *
     * @param key       Redis 键
     * @param hashKey   哈希键
     * @param value     存储的值
     * @param timeout   过期时间
     * @param timeUnit  时间单位
     * @param <T>       值的类型
     * @return 是否成功设置过期时间
     */
    public <T> Boolean setHash(String key, String hashKey, T value, long timeout, TimeUnit timeUnit) {
        redisTemplate.opsForHash().put(key, hashKey, value);
        return setExpire(key, timeout, timeUnit);
    }

    /**
     * 设置 Redis 中哈希类型的数据(批量设置)
     *
     * @param key Redis 键
     * @param map 存储的键值对集合
     * @param <T> 值的类型
     */
    public <T> void setHashAll(String key, Map<String, T> map) {
        redisTemplate.opsForHash().putAll(key, map);
    }

    /**
     * 设置 Redis 中哈希类型的数据(批量设置),并设置过期时间
     *
     * @param key       Redis 键
     * @param map       存储的键值对集合
     * @param timeout   过期时间
     * @param timeUnit  时间单位
     * @param <T>       值的类型
     * @return 是否成功设置过期时间
     */
    public <T> Boolean setHashAll(String key, Map<String, T> map, long timeout, TimeUnit timeUnit) {
        redisTemplate.opsForHash().putAll(key, map);
        return setExpire(key, timeout, timeUnit);
    }

    /**
     * 获取 Redis 中哈希类型的数据
     *
     * @param key     Redis 键
     * @param hashKey 哈希键
     * @param <T>     值的类型
     * @return Redis 存储的值
     */
    public <T> T getHash(String key, String hashKey) {
        return (T) redisTemplate.opsForHash().get(key, hashKey);
    }

    /**
     * 获取 Redis 中哈希类型的所有数据
     *
     * @param key Redis 键
     * @return 键值对集合
     */
    public Map getHashAll(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * 删除 Redis 中哈希类型的数据
     *
     * @param key       Redis 键
     * @param hashKeys  哈希键
     * @param <T>       值的类型
     */
    public <T> void deleteHash(String key, T... hashKeys) {
        redisTemplate.opsForHash().delete(key, hashKeys);
    }

    /**
     * 判断 Redis 中是否存在指定哈希类型的数据
     *
     * @param key     Redis 键
     * @param hashKey 哈希键
     * @return 是否存在指定哈希键
     */
    public Boolean hasHashValue(String key, String hashKey) {
        return redisTemplate.opsForHash().hasKey(key, hashKey);
    }

    /**
     * 对 Redis 中哈希类型的数据进行递增操作
     *
     * @param key     Redis 键
     * @param hashKey 哈希键
     * @param delta   增加的值
     * @return 增加后的值
     */
    public Long incrHash(String key, String hashKey, Long delta) {
        return redisTemplate.opsForHash().increment(key, hashKey, delta);
    }

    /**
     * 对 Redis 中哈希类型的数据进行递减操作
     *
     * @param key     Redis 键
     * @param hashKey 哈希键
     * @param delta   减少的值
     * @return 减少后的值
     */
    public Long decrHash(String key, String hashKey, Long delta) {
        return redisTemplate.opsForHash().increment(key, hashKey, -delta);
    }

    /**
     * 将数据添加到 Redis 中的列表类型
     *
     * @param key   Redis 键
     * @param value 存储的值
     * @param <T>   值的类型
     * @return 添加后的列表长度
     */
    public <T> Long setList(String key, T value) {
        return redisTemplate.opsForList().rightPush(key, value);
    }

    /**
     * 将数据添加到 Redis 中的列表类型,并设置过期时间
     *
     * @param key       Redis 键
     * @param value     存储的值
     * @param timeout   过期时间
     * @param timeUnit  时间单位
     * @param <T>       值的类型
     * @return 添加后的列表长度
     */
    public <T> Long setList(String key, T value, long timeout, TimeUnit timeUnit) {
        Long count = redisTemplate.opsForList().rightPush(key, value);
        setExpire(key, timeout, timeUnit);
        return count;
    }

    /**
     * 将数据批量添加到 Redis 中的列表类型
     *
     * @param key    Redis 键
     * @param values 存储的值集合
     * @param <T>    值的类型
     * @return 添加后的列表长度
     */
    public <T> Long setListAll(String key, T... values) {
        return redisTemplate.opsForList().rightPushAll(key, values);
    }

    /**
     * 将数据批量添加到 Redis 中的列表类型,并设置过期时间
     *
     * @param key       Redis 键
     * @param timeout   过期时间
     * @param timeUnit  时间单位
     * @param values    存储的值集合
     * @param <T>       值的类型
     * @return 添加后的列表长度
     */
    public <T> Long setListAll(String key, long timeout, TimeUnit timeUnit, T... values) {
        Long count = redisTemplate.opsForList().rightPushAll(key, values);
        setExpire(key, timeout, timeUnit);
        return count;
    }

    /**
     * 获取 Redis 中列表类型数据的指定范围(索引)
     *
     * @param key   Redis 键
     * @param start 起始索引
     * @param end   结束索引
     * @param <T>   值的类型
     * @return 指定范围内的列表数据
     */
    public <T> List<T> getList(String key, long start, long end) {
        List<T> result = (List<T>) redisTemplate.opsForList().range(key, start, end);
        return result;
    }

    /**
     * 获取 Redis 中列表类型数据的指定索引值
     *
     * @param key   Redis 键
     * @param index 索引值
     * @param <T>   值的类型
     * @return 列表中指定索引的数据
     */
    public <T> T getListByIndex(String key, long index) {
        return (T) redisTemplate.opsForList().index(key, index);
    }

    /**
     * 获取 Redis 中列表类型的大小
     *
     * @param key Redis 键
     * @return 列表长度
     */
    public Long getListSize(String key) {
        return redisTemplate.opsForList().size(key);
    }

    /**
     * 删除 Redis 中列表类型的指定数据
     *
     * @param key   Redis 键
     * @param count 删除的数量
     * @param value 要删除的值
     * @param <T>   值的类型
     * @return 删除的数量
     */
    public <T> Long deleteList(String key, long count, T value) {
        return redisTemplate.opsForList().remove(key, count, value);
    }

    /**
     * 将数据添加到 Redis 中的集合类型
     *
     * @param key    Redis 键
     * @param values 存储的值集合
     * @param <T>    值的类型
     * @return 添加的元素数量
     */
    public <T> Long setSet(String key, T... values) {
        return redisTemplate.opsForSet().add(key, values);
    }

    /**
     * 将数据添加到 Redis 中的集合类型,并设置过期时间
     *
     * @param key       Redis 键
     * @param timeout   过期时间
     * @param timeUnit  时间单位
     * @param values    存储的值集合
     * @param <T>       值的类型
     * @return 添加的元素数量
     */
    public <T> Long setSet(String key, long timeout, TimeUnit timeUnit, T... values) {
        Long count = redisTemplate.opsForSet().add(key, values);
        setExpire(key, timeout, timeUnit);
        return count;
    }

    /**
     * 获取 Redis 中集合类型的数据
     *
     * @param key Redis 键
     * @param <T> 值的类型
     * @return 集合数据
     */
    public <T> Set<T> getSet(String key) {
        Set<T> result = (Set<T>) redisTemplate.opsForSet().members(key);
        return result;
    }

    /**
     * 删除 Redis 中集合类型的数据
     *
     * @param key    Redis 键
     * @param values 要删除的值集合
     * @param <T>    值的类型
     * @return 删除的元素数量
     */
    public <T> Long deleteSet(String key, T... values) {
        return redisTemplate.opsForSet().remove(key, values);
    }

    /**
     * 判断 Redis 中集合类型的数据是否包含指定的值
     *
     * @param key   Redis 键
     * @param value 要检查的值
     * @param <T>   值的类型
     * @return 是否包含指定的值
     */
    public <T> Boolean hasSetValue(String key, T value) {
        return redisTemplate.opsForSet().isMember(key, value);
    }

    /**
     * 获取 Redis 中集合类型数据的大小
     *
     * @param key Redis 键
     * @return 集合长度
     */
    public Long getSetSize(String key) {
        return redisTemplate.opsForSet().size(key);
    }

    /**
     * 对 Redis 中的有序集合进行递增操作
     *
     * @param key   Redis 键
     * @param value 元素值
     * @param score 增加的分值
     * @param <T>   值的类型
     * @return 增加后的分值
     */
    public <T> Double incrZet(String key, T value, Double score) {
        return redisTemplate.opsForZSet().incrementScore(key, value, score);
    }

    /**
     * 对 Redis 中的有序集合进行递减操作
     *
     * @param key   Redis 键
     * @param value 元素值
     * @param score 减少的分值
     * @param <T>   值的类型
     * @return 减少后的分值
     */
    public <T> Double decrZet(String key, T value, Double score) {
        return redisTemplate.opsForZSet().incrementScore(key, value, -score);
    }

    /**
     * 删除 Redis 中有序集合的数据
     *
     * @param key    Redis 键
     * @param values 要删除的元素值
     * @param <T>    值的类型
     * @return 删除的元素数量
     */
    public <T> Long deleteZetScore(String key, T... values) {
        return redisTemplate.opsForZSet().remove(key, values);
    }

    /**
     * 获取 Redis 中有序集合的指定范围内的数据(按分值倒序)
     *
     * @param key   Redis 键
     * @param start 起始索引
     * @param end   结束索引
     * @return 元素及其分值的集合
     */
    public Map<Object, Double> zReverseRangeWithScore(String key, long start, long end) {
        return redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end)
                .stream()
                .collect(Collectors.toMap(ZSetOperations.TypedTuple::getValue, ZSetOperations.TypedTuple::getScore));
    }

    /**
     * 获取 Redis 中有序集合中指定元素的分值
     *
     * @param key   Redis 键
     * @param value 元素值
     * @param <T>   值的类型
     * @return 分值
     */
    public <T> Double getZsetScore(String key, T value) {
        return redisTemplate.opsForZSet().score(key, value);
    }

    /**
     * 获取 Redis 中有序集合所有元素及其分值
     *
     * @param key Redis 键
     * @return 元素及其分值的集合
     */
    public Map<Object, Double> getZsetAllScore(String key) {
        return Objects.requireNonNull(redisTemplate.opsForZSet().rangeWithScores(key, 0, -1))
                .stream()
                .collect(Collectors.toMap(ZSetOperations.TypedTuple::getValue, ZSetOperations.TypedTuple::getScore));
    }
}

;