SpringBoot+Redis使用jedis实现了对Redis基本类型操作超全工具类

这编文章主要介绍了springboot整合redis,使用jedis实现了对Redis基本类型操作,一些redis的常用命令总结到了一个公共的工具类中,其中使用了fastjson作为了序列化工具。
注:使用了 jdk 1.8 新特性 ,jdk版本需要>=1.8

一.添加maven依赖

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.12.RELEASE</version>
    </parent>
    <!--统一版本号配置 -->
    <properties>
        <fastjson.version>1.2.47</fastjson.version>
        <redis.clients.version>2.9.0</redis.clients.version>
    </properties>
    <dependencies>
        <!-- springBoot 相关 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>
        <!-- redis client -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>${redis.clients.version}</version>
        </dependency>
        <!-- json -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fastjson.version}</version>
        </dependency>
    </dependencies>

二.配置文件
创建一个application.properties 配置文件

#端口配置
server.port=8081

#redis 基础配置
# Redis数据库索引(默认为0)
spring.redis.database=1
# Redis服务器地址
spring.redis.host=127.0.0.1
# Redis服务器连接密码(默认为空)
spring.redis.password=123456
# Redis服务器连接端口
spring.redis.port=6379
# 连接超时时间(毫秒)
spring.redis.timeout=0

#redis 连接池配置
#池中最大链接数
spring.redis.pool-config.max-total=256
# 连接池中的最大空闲连接
spring.redis.pool-config.max-idle=128
# 连接池中的最小空闲连接
spring.redis.pool-config.min-idle=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool-config.max-wait-millis=1000
# 调用者获取链接时,是否检测当前链接有效性
spring.redis.pool-config.test-on-borrow=false
# 向链接池中归还链接时,是否检测链接有效性
spring.redis.pool-config.test-on-return=false
# 调用者获取链接时,是否检测空闲超时, 如果超时,则会被移除-
spring.redis.pool-config.test-while-idle=true
# 空闲链接检测线程一次运行检测多少条链接
spring.redis.pool-config.num-tests-per-eviction-run=8
#空闲链接检测线程检测周期。如果为负值,表示不运行检测线程。(单位:毫秒,默认为-1)
spring.redis.pool-config.time-between-eviction-runs-millis=60000
#配置一个连接在池中最小生存的时间,单位是毫秒
spring.redis.pool-config.min-evictable-idle-time-millis=300000

#spring-session
spring.session.store-type=none
#日志配置
logging.level.root=WARN
logging.level.net.sf=WARN
logging.level.com.boot.redis=TRACE

三、代码实现
1)创建启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
/**
 * 启动类
 * springboot启动时会自动注入数据源和配置jpa 在不连接数据库情况下需要移除
 */
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

由于不需要使用mysql等数据库所以移除默认数据源配置

2)创建一个RedisConfigProperties的配置类方便直接使用配置的参数

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
 * redis 配置属性类
 */
@Configuration
@ConfigurationProperties(prefix = "spring.redis")
public class RedisConfigProperties {
    /**
     * Redis服务器地址
     */
    private String host;
    /**
     * Redis服务器连接密码(默认为空)
     */
    private String password;
    /**
     * Redis数据库索引(默认为0)
     */
    private int database;
    /**
     * Redis服务器连接端口
     */
    private int port;
    /**
     * 连接超时时间(毫秒)
     */
    private int timeout;
    //省略 get/set方法
}

3)创建JedisConfig

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
/**
 * 配置类
 */
@Configuration
public class JedisConfig extends CachingConfigurerSupport {
    private Logger LOGGER = LoggerFactory.getLogger(JedisConfig.class);
    @Autowired
    private RedisConfigProperties redisConfigProperties;

    @Bean(name = "jedisPoolConfig")
    @ConfigurationProperties(prefix = "spring.redis.pool-config")
    public JedisPoolConfig getRedisConfig() {
        JedisPoolConfig config = new JedisPoolConfig();
        return config;
    }
    @Bean(name = "jedisPool")
    public JedisPool jedisPool(@Qualifier(value = "jedisPoolConfig") final JedisPoolConfig jedisPoolConfig) {
        LOGGER.info("Jedis Pool build start ");
        String host = redisConfigProperties.getHost();
        Integer timeout = redisConfigProperties.getTimeout();
        int port = redisConfigProperties.getPort();
        String password = redisConfigProperties.getPassword();
        int database = redisConfigProperties.getDatabase();
        JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout, password, database);
        LOGGER.info("Jedis Pool build success  host={} , port={}", host, port);
        return jedisPool;
    }
}

创建序列化工具类

import com.alibaba.fastjson.JSON;
import java.nio.charset.Charset;
/**
 * json  Serializer util
 */
public class JsonSerializer {
    public static final String UTF_8 = "UTF-8";
    /**
     * @param obj
     * @param 
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> byte[] serialize(T obj) {
        return JSON.toJSONString(obj).getBytes(Charset.forName(UTF_8));
    }
    /**
     * @param data
     * @param clazz
     * @param 
     * @return
     */
    public static <T> T deserialize(byte[] data, Class<T> clazz) {
        return JSON.parseObject(data, clazz);
    }
}

创建时间计算工具类

import java.util.concurrent.TimeUnit;
/**
 * 时间计算工具类
 */
public class TimeUnitUtil {
    /**
     * 时间秒数计算
     *
     * @param timeUnit 单位枚举
     * @param duration 时间量
     * @return 秒数
     */
    public static int getSeconds(TimeUnit timeUnit, int duration) {
        return (int) timeUnit.toSeconds(duration);
    }
    /**
     * 时间毫秒数计算
     *
     * @param timeUnit 单位枚举
     * @param duration 时间量
     * @return 毫秒数
     */
    public static long getMillis(TimeUnit timeUnit, int duration) {
        return timeUnit.toMillis(duration);
    }
}

创建时间戳工具类SystemClock

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
/**
 * 高并发场景下System.currentTimeMillis()的性能问题的优化
 * 时间戳打印建议使用
 */
public class SystemClock {
    private static final String THREAD_NAME = "system.clock";
    private static final SystemClock MILLIS_CLOCK = new SystemClock(1);
    private final long precision;
    private final AtomicLong now;

    private SystemClock(long precision) {
        this.precision = precision;
        now = new AtomicLong(System.currentTimeMillis());
        scheduleClockUpdating();
    }
    public static SystemClock millisClock() {
        return MILLIS_CLOCK;
    }
    private void scheduleClockUpdating() {
        ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(runnable -> {
            Thread thread = new Thread(runnable, THREAD_NAME);
            thread.setDaemon(true);
            return thread;
        });
        scheduler.scheduleAtFixedRate(() -> now.set(System.currentTimeMillis()), precision, precision, TimeUnit.MILLISECONDS);
    }
    public long now() {
        return now.get();
    }
}

这里未使用 java 自带的 System.currentTimeMillis() 作为时间戳,
具体原因请至上一篇博客https://blog.csdn.net/qq_38011415/article/details/82813299

创建redis 客户端接口

import redis.clients.jedis.Jedis;
import java.io.IOException;
public interface RedisClientInvoker<T> {
    T invoke(Jedis jedis) throws IOException;
}

创建redis 客户端工具类

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.exceptions.JedisException;
import java.io.IOException;
@Component
public class RedisClient {
    private static final Logger LOGGER = LoggerFactory.getLogger(RedisClient.class);
    public  T invoke(JedisPool pool, RedisClientInvoker clients) {
        T obj = null;
        Jedis jedis = null;
        boolean broken = false;
        try {
            jedis = pool.getResource();
            obj = clients.invoke(jedis);
        } catch (JedisException | IOException ex) {
            LOGGER.error(ex.getMessage(), ex);
        } finally {
            if (jedis != null) {
                if (jedis.isConnected())
                jedis.close();
            }
        }
        return obj;
    }
}

创建Redis缓存实现公共工具类

import com.alibaba.fastjson.JSONArray;
import com.boot.redis.util.JsonSerializer;
import com.boot.redis.util.SystemClock;
import com.boot.redis.util.TimeUnitUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import redis.clients.jedis.BinaryJedis;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.nio.charset.Charset;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Component
public class RedisCache {

    private static final Logger LOGGER = LoggerFactory.getLogger(RedisCache.class);
    private static final int ZERO = 0;
    private static final int FIVE = 5;
    private static final String OK = "OK";
    private static final Long LONG_ZERO = 0l;
    /**
     * 默认失效时间5 分钟
     */
    public static final int DEFAULT_CACHE_SECONDS = TimeUnitUtil.getSeconds(TimeUnit.SECONDS, FIVE);

    /**
     * 默认失效时间毫秒 5 分钟
     */
    public static final long DEFAULT_CACHE_MILLIS = TimeUnitUtil.getMillis(TimeUnit.MINUTES, FIVE);

    @Autowired
    private JedisPool jedisPool;
    @Autowired
    private RedisClient redisClient;


    /**------------------key 普通 相关操作--------------------------------*/
    /**
     * 是否存在校验
     *
     * @param key
     * @return 是否存在
     */
    public boolean exists(String key) {
        validateKeyParam(key);
        return redisClient.invoke(jedisPool, (jedis) -> jedis.exists(key.getBytes()));
    }

    /**
     * 用于设置 key 的过期时间,
     * key 过期后将不再可用。单位以秒计
     *
     * @param key
     * @return 是否设置成功
     */
    public Boolean expire(String key, int seconds) {
        return this.expire(key, seconds, TimeUnit.SECONDS);
    }

    /**
     * 用于设置 key 的过期时间,key 过期后将不再可用。
     * 设置成功返回 1
     * 当 key 不存在或者不能为 key 设置过期时间时返回 0
     * 

* 时间枚举介绍 * TimeUnit.DAYS //天 * TimeUnit.HOURS //小时 * TimeUnit.MINUTES //分钟 * TimeUnit.SECONDS //秒 * TimeUnit.MILLISECONDS //毫秒 * TimeUnit.NANOSECONDS //毫微秒 * TimeUnit.MICROSECONDS //微秒 * * @param key * @param duration 时间量与单位一起使用 * @param timeUnit 单位枚举类 * @return */ public Boolean expire(String key, int duration, TimeUnit timeUnit) { validateKeyParam(key); //时间转换成毫秒 long millis = TimeUnitUtil.getMillis(timeUnit, duration); Long lResult = redisClient.invoke(jedisPool, (jedis) -> jedis.pexpire(key.getBytes(), millis)); if (LONG_ZERO.equals(lResult)) { return false; } return true; } /** * 根据key 获取过期时间秒数 * 不存在时返回负数 * * @param key * @return 剩余过期时间秒数 * 当 key 不存在时,返回 -2 。 * 当 key 存在但没有设置剩余生存时间时,返回 -1 。 * 否则,以秒为单位,返回 key 的剩余生存时间 */ public Long getExpiresTtl(String key) { validateKeyParam(key); return redisClient.invoke(jedisPool, (jedis) -> jedis.ttl(key.getBytes())); } /** * 根据key 获取过期时间毫秒数 * 不存在时返回负数 * * @param key * @return 剩余过期时间毫秒数 * 当 key 不存在时,返回 -2 * 当 key 存在但没有设置剩余生存时间时,返回 -1 * 否则,以毫秒为单位,返回 key 的剩余生存时间 */ public Long getExpiresPttl(String key) { validateKeyParam(key); return redisClient.invoke(jedisPool, (jedis) -> jedis.pttl(key.getBytes())); } /** * 移除 key 的过期时间,key 将持久保持。 * 当过期时间移除成功时,返回 1 * 如果 key 不存在或 key 没有设置过期时间,返回 0 * * @param key */ public Long persist(String key) { validateKeyParam(key); return redisClient.invoke(jedisPool, (jedis) -> jedis.persist(key.getBytes())); } /** * 根据key 获取存储类型 * * @param key * @return 返回 key 的数据类型,数据类型有: * none (key不存在) * string (字符串) * list (列表) * set (集合) * zset (有序集) * hash (哈希表) */ public String getType(String key) { validateKeyParam(key); return redisClient.invoke(jedisPool, (jedis) -> jedis.type(key.getBytes())); } /** * 根据key移除 * * @param key */ public void remove(String key) { validateKeyParam(key); if (exists(key)) { redisClient.invoke(jedisPool, (jedis) -> jedis.del(key.getBytes())); } } /**------------------字符串相关操作--------------------------------*/ /** * 添加数据到redis * 设置默认过期时间 5 分钟 * * @param key * @param value */ public Boolean put(String key, Object value) { return put(key, value, FIVE, TimeUnit.MINUTES); } /** * 添加数据到redis * 自定义过期时间 * 注:从 Redis 2.6.12 版本开始, SET 在设置操作成功完成时,返回 OK * * @param key * @param value * @param duration 时间量 * @param timeUnit 时间单位枚举 */ public Boolean put(String key, Object value, int duration, TimeUnit timeUnit) { validateParam(key, value); String result = redisClient.invoke(jedisPool, (jedis) -> { String srtResult = jedis.set(key.getBytes(), JsonSerializer.serialize(value)); if (duration <= ZERO) { //默认5 分钟 jedis.pexpire(key.getBytes(), DEFAULT_CACHE_MILLIS); } else { //时间转换成毫秒 long millis = TimeUnitUtil.getMillis(timeUnit, duration); jedis.pexpire(key.getBytes(), millis); } return srtResult; } ); if (OK.equals(result)) { return true; } return false; } /** * 添加数据到redis * 并设置永不过期 * 注:一般使用较少,数据过大时尽量不要使用 * 从 Redis 2.6.12 版本开始, SET 在设置操作成功完成时,返回 OK * * @param key * @param value */ public Boolean putNeverExpires(String key, Object value) { validateParam(key, value); String result = redisClient.invoke(jedisPool, (jedis) -> { String srtResult = jedis.set(key.getBytes(), JsonSerializer.serialize(value)); return srtResult; } ); if (OK.equals(result)) { return true; } return false; } /** * 根据key 获取值 * * @param key * @param clazz 类class * @return 类对象 */ public <T> T get(String key, Class<T> clazz) { validateKeyParam(key); byte[] result = redisClient.invoke(jedisPool, (jedis) -> jedis.get(key.getBytes())); if (result == null) { return null; } return JsonSerializer.deserialize(result, clazz); } /** * 根据key 获取值 * 返回 key 的值,如果 key 不存在时,返回 nil。 * 如果 key 不是字符串类型,那么返回一个错误。 * * @param key * @return String */ public String get(String key) { return this.get(key, String.class); } /** * 根据key 获取值 * * @param key * @param clazz 集合泛型对象 * @return 集合对象 */ public <T> List<T> getList(String key, Class<T> clazz) { String str = this.get(key, String.class); return JSONArray.parseArray(str, clazz); } /** * 将key 的值设为 value ,当且仅当 key 不存在 * more值是时间戳 默认有效期是 5 分钟 * * @param key * @return 设置成功返回 true 失败返回false */ public boolean setNx(String key) { return this.setNx(key, SystemClock.millisClock().now(), FIVE, TimeUnit.MINUTES); } /** * 将key 的值设为 value ,当且仅当 key 不存在 * 默认有效期是 5 分钟 * * @param key * @param value 自定义值 * @return 设置成功返回 true 失败返回false */ public boolean setNx(String key, Object value) { return this.setNx(key, value, FIVE, TimeUnit.MINUTES); } /** * 将key 的值设为 value ,当且仅当 key 不存在 * more值是时间戳 * * @param key * @param seconds 自定义过期时间秒数 * @return 设置成功返回 true 失败返回false */ public boolean setNx(String key, int seconds) { return this.setNx(key, SystemClock.millisClock().now(), seconds, TimeUnit.SECONDS); } /** * 将key 的值设为 value ,当且仅当 key 不存在 * 默认时间单位是秒 * * @param key * @param value 自定义 value * @param seconds 自定义过期时间秒数 * @return 设置成功返回 true 失败返回false */ public boolean setNx(String key, Object value, int seconds) { return this.setNx(key, value, seconds, TimeUnit.SECONDS); } /** * 将key 的值设为 value ,当且仅当 key 不存在 * 注:常用与分布式锁 * * @param key * @param value * @param duration 时间量 * @param timeUnit 时间单位枚举 * @return 设置成功返回 true 失败返回false */ public boolean setNx(String key, Object value, int duration, TimeUnit timeUnit) { validateParam(key, value); return redisClient.invoke(jedisPool, (jedis) -> { long result = jedis.setnx(key.getBytes(), JsonSerializer.serialize(value)); if (result >= 1) { if (duration <= ZERO) { //默认5 分钟 jedis.pexpire(key.getBytes(), DEFAULT_CACHE_MILLIS); return true; } else { //时间转换成毫秒 long millis = TimeUnitUtil.getMillis(timeUnit, duration); jedis.pexpire(key.getBytes(), millis); return true; } } else { return false; } } ); } /** * 设置指定 key 的值,并返回 key 的旧值 * 返回给定 key 的旧值。 当 key 没有旧值时,即 key 不存在时,返回 null * 注:默认有效期为 5分钟 * * @param key * @return String */ public String getSet(String key, String value) { return this.getSet(key, value, FIVE, TimeUnit.MINUTES); } /** * 设置指定 key 的值,并返回 key 的旧值 * 返回给定 key 的旧值。 当 key 没有旧值时,即 key 不存在时,返回 null * * @param key * @return string key 的旧值 */ public String getSet(String key, String value, int duration, TimeUnit timeUnit) { validateParam(key, value); return redisClient.invoke(jedisPool, (jedis) -> { String result = jedis.getSet(key, value); if (duration <= ZERO) { //设置默认过期时间 5 分钟 jedis.pexpire(key.getBytes(), DEFAULT_CACHE_MILLIS); return result; } else { //时间转换成毫秒 long millis = TimeUnitUtil.getMillis(timeUnit, duration); jedis.pexpire(key.getBytes(), millis); return result; } } ); } /** * 用于获取指定 key 所储存的字符串值的长度。 * 当 key 储存的不是字符串值时,返回一个错误 * 当 key 不存在时,返回 0 * * @param key */ public Long getStrLen(String key) { validateKeyParam(key); return redisClient.invoke(jedisPool, (jedis) -> jedis.strlen(key.getBytes())); } /** * key 中储存的数字值增一 (默认增量+1) * 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。 * 注: * 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。 * 本操作的值限制在 64 位(bit)有符号数字表示之内 * * @param key * @return 执行命令之后 key 的值。 */ public Long incr(String key) { validateKeyParam(key); return redisClient.invoke(jedisPool, (jedis) -> jedis.incr(key.getBytes())); } /** * key 中储存的数字值增一 (自定义增量值 ) * 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。 * 注: * 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。 * 本操作的值限制在 64 位(bit)有符号数字表示之内 * * @param key * @param value 自定义增量值 * @return 执行命令之后 key 的值。 */ public Long incr(String key, long value) { validateKeyParam(key); return redisClient.invoke(jedisPool, (jedis) -> jedis.incrBy(key.getBytes(), value)); } /** * 为 key 中所储存的值加上指定的浮点数增量值 * 如果 key 不存在,那么 incrbyfloat 会先将 key 的值设为 0 ,再执行加法操作。 * * @param key * @param value 增量值 * @return 执行命令之后 key 的值。 */ public Double incr(String key, Double value) { validateKeyParam(key); return redisClient.invoke(jedisPool, (jedis) -> jedis.incrByFloat(key.getBytes(), value)); } /** * 将 key 中储存的数字值减一 *

* 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECR 操作。 * 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。 * 本操作的值限制在 64 位(bit)有符号数字表示之内。 * * @param key * @return 执行命令之后 key 的值。 */ public Long decr(String key) { validateKeyParam(key); return redisClient.invoke(jedisPool, (jedis) -> jedis.decr(key.getBytes())); } /** * 将 key 中储存的数字值减一 *

* 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECR 操作。 * 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。 * 本操作的值限制在 64 位(bit)有符号数字表示之内。 * * @param key * @param value 自定义减量值 * @return 执行命令之后 key 的值。 */ public Long decr(String key, long value) { validateKeyParam(key); return redisClient.invoke(jedisPool, (jedis) -> jedis.decrBy(key.getBytes(), value)); } /** * 用于为指定的 key 追加值。 *

* 如果 key 已经存在并且是一个字符串, APPEND 命令将 value * 追加到 key 原来的值的末尾。 * 如果 key 不存在, APPEND 就简单地将给定 key 设为 value , * 就像执行 SET key value 一样。 * * @param key * @param value * @return 追加指定值之后, key 中字符串的长度。 */ public Long append(String key, Object value) { validateKeyParam(key); return redisClient.invoke(jedisPool, (jedis) -> jedis.append(key.getBytes(), JsonSerializer.serialize(value))); } /**------------------zSet相关操作--------------------------------*/ /** * 添加元素到有序集合,有序集合是按照元素的score进行排列 * 注意: 在 Redis 2.4 版本以前, ZADD 每次只能添加一个元素。 * 当 key 存在但不是有序集类型时,返回一个错误。 * * @param key * @param obj * @param score 分值 */ public void zAddByScore(String key, Object obj, double score) { validateParam(key, obj); redisClient.invoke(jedisPool, jedis -> { jedis.zadd(key.getBytes(), score, JsonSerializer.serialize(obj)); return null; }); } /** * 根据key 计算集合中元素的数量 * * @param key * @return 当 key 存在且是有序集类型时,返回有序集的基数。 当 key 不存在时,返回 0 */ public long zCard(String key) { validateKeyParam(key); long count = redisClient.invoke(jedisPool, jedis -> { long result = jedis.zcard(key.getBytes()); return result; }); return count; } /** * 根据key 计算在有序集合中指定区间分数的成员数 * * @param key * @param minScore 最小排序分值 * @param maxScore 最大排序分值 * @return 分数值在 min 和 max 之间的成员的数量。 */ public long zCount(String key, double minScore, double maxScore) { validateKeyParam(key); long count = redisClient.invoke(jedisPool, jedis -> { long result = jedis.zcount(key.getBytes(), minScore, maxScore); return result; }); return count; } /** * 返回有序集中,指定区间内的成员 -> 从小到大 * 其中成员的位置按分数值递增(从小到大)来排序 *

* 具有相同分数值的成员按字典序来排列 * 注意:下标参数0 为起始 * 负数下标,以 -1 表示最后一个成员, -2 表示倒数第二个成员,以此类推 * * @param key * @param clazz * @param start 开始位置 * @param end 结束位置 * @return 相应对象集合 */ public <T> List<T> zRange(String key, Class<T> clazz, int start, int end) { validateKeyParam(key); List<T> result = redisClient.invoke(jedisPool, jedis -> { Set<byte[]> set = jedis.zrange(key.getBytes(), start, end); List<T> list = new ArrayList<>(set.size()); if (CollectionUtils.isEmpty(set)) { return new ArrayList<T>(ZERO); } for (byte[] bytes : set) { T t = JsonSerializer.deserialize(bytes, clazz); list.add(t); } return list; }); return result; } /** * 返回有序集中,指定区间内的成员 -> 从大到小 * 其中成员的位置按分数值递增(从大到小)来排序 * * @param key * @param clazz * @param start 开始位置 * @param end 结束位置 * @return 指定区间内,带有分数值的有序集成员的列表。 */ public <T> List<T> zRevRange(String key, Class<T> clazz, int start, int end) { validateKeyParam(key); List<T> result = redisClient.invoke(jedisPool, jedis -> { Set<byte[]> set = jedis.zrevrange(key.getBytes(), start, end); List<T> list = new ArrayList<>(set.size()); if (CollectionUtils.isEmpty(set)) { return new ArrayList<T>(ZERO); } for (byte[] bytes : set) { T t = JsonSerializer.deserialize(bytes, clazz); list.add(t); } return list; }); return result; } /** * 通过分数返回有序集合指定区间内的成员 -> 从小到大 * 有序集成员按分数值递增(从小到大)次序排列 * * @param key * @param clazz * @param minScore 最小分数 * @param maxScore 最大分数 * @return 指定区间内,带有分数值(可选)的有序集成员的列表。 */ public <T> List<T> zRangeByScore(String key, Class<T> clazz, double minScore, double maxScore) { validateKeyParam(key); List<T> result = redisClient.invoke(jedisPool, jedis -> { Set<byte[]> set = jedis.zrangeByScore(key.getBytes(), minScore, maxScore); List<T> list = new ArrayList<>(set.size()); if (CollectionUtils.isEmpty(set)) { return new ArrayList<T>(ZERO); } for (byte[] bytes : set) { T t = JsonSerializer.deserialize(bytes, clazz); list.add(t); } return list; }); return result; } /** * 通过分数返回有序集合指定区间内的成员 -> 从大到小 * 有序集成员按分数值递增(从大到小)次序排列 * * @param key * @param clazz * @param minScore 最小分数 * @param maxScore 最大分数 * @return 指定区间内,带有分数值(可选)的有序集成员的列表。 */ public <T> List<T> zRevRangeByScore(String key, Class<T> clazz, double minScore, double maxScore) { validateKeyParam(key); List<T> result = redisClient.invoke(jedisPool, jedis -> { Set<byte[]> set = jedis.zrevrangeByScore(key.getBytes(), maxScore, minScore); List<T> list = new ArrayList<>(set.size()); if (CollectionUtils.isEmpty(set)) { return new ArrayList<T>(ZERO); } for (byte[] bytes : set) { T t = JsonSerializer.deserialize(bytes, clazz); list.add(t); } return list; }); return result; } /** * 返回有序集中指定成员的排名 * 按分数值递增(从小到大)顺序排列 * 排名以 0 为底,也就是说, 分数值最小的成员排名为 0 * * @param key * @param obj 成员对象 * @return 如果成员是有序集 key 的成员,返回 member 的排名。 * 如果成员不是有序集 key 的成员,返回空 */ public long zRank(String key, Object obj) { validateParam(key, obj); long sortIndex = redisClient.invoke(jedisPool, jedis -> { long result = jedis.zrank(key.getBytes(), JsonSerializer.serialize(obj)); return result; }); return sortIndex; } /** * 返回有序集中指定成员的排名 * 分数值递减(从大到小)排序 * 排名以 0 为底,也就是说, 分数值最大的成员排名为 0 * * @param key * @param obj 成员对象 * @return 如果成员是有序集 key 的成员,返回 member 的排名。 * 如果成员不是有序集 key 的成员,返回空 */ public long zRevRank(String key, Object obj) { validateParam(key, obj); long sortIndex = redisClient.invoke(jedisPool, jedis -> { long result = jedis.zrevrank(key.getBytes(), JsonSerializer.serialize(obj)); return result; }); return sortIndex; } /** * 移除有序集合中的个成员 * 名称为key 的有序集合中的元素 obj * * @param key * @param obj 元素 * @return 被成功移除的成员的数量,不包括被忽略的成员。 */ public long zRem(String key, Object obj) { validateParam(key, obj); long lRow = redisClient.invoke(jedisPool, jedis -> { long result = jedis.zrem(key.getBytes(), JsonSerializer.serialize(obj)); return result; }); return lRow; } /** * 移除有序集合中给定的排名区间的所有成员 * 从排序小的开始删除 * * @param start 开始位置 下标 0 开始 * @param end 结束位置 * @return 被移除成员的数量。 */ public long zRemRangeByRank(String key, int start, int end) { validateKeyParam(key); long lRow = redisClient.invoke(jedisPool, jedis -> { long result = jedis.zremrangeByRank(key.getBytes(), start, end); return result; }); return lRow; } /** * 返回有序集中,成员的分数值 * 如果成员元素不是有序集 key 的成员,或 key 不存在,返回 null * * @param key * @param obj 成员对象 * @return 如果成员是有序集 key 的成员,返回 member 的排名。 * 如果成员不是有序集 key 的成员,返回空 */ public Double zScore(String key, Object obj) { validateParam(key, obj); Double score = redisClient.invoke(jedisPool, jedis -> { Double sResult = jedis.zscore(key.getBytes(), JsonSerializer.serialize(obj)); return sResult; }); return score; } /** * -------------------list相关操作--------------------- */ /** * 将一个或多个值插入到列表头部 * 如果 key 不存在,一个空列表会被创建并执行 LPUSH 操作。 * 当 key 存在但不是列表类型时,返回一个错误 * 注意:在Redis 2.4版本以前的 lpush 命令,都只接受单个 value 值。 * * @param key * @return 列表的长度。 */ public Long lpush(String key, Object... value) { validateParam(key, value); Long len = redisClient.invoke(jedisPool, jedis -> { return jedis.lpush(key.getBytes(), JsonSerializer.serialize(value)); }); return len; } /** * 用于返回列表的长度 * 如果列表 key 不存在,则 key 被解释为一个空列表, * 返回 0 。 如果 key 不是列表类型,返回一个错误 * * @param key * @return list 集大小 */ public long lLen(String key) { validateKeyParam(key); long count = redisClient.invoke(jedisPool, jedis -> { long countAll = jedis.llen(key.getBytes()); return countAll; }); return count; } /** * 通过索引获取列表中的元素 * 如果指定索引值不在列表的区间范围内,返回 null * 使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。 * * @param key * @param index 集合索引 * @return 元素信息 */ public <T> T lindex(String key, int index, Class<T> clazz) { validateParam(key, clazz); T obj = redisClient.invoke(jedisPool, jedis -> { byte[] result = jedis.lindex(key.getBytes(), index); if (result == null) { return null; } return JsonSerializer.deserialize(result, clazz); }); return obj; } /** * 移除并返回列表的第一个元素 * * @param key * @return 列表的第一个元素。 当列表 key 不存在时,返回 null。 */ public <T> T lpop(String key, Class<T> clazz) { validateParam(key, clazz); T obj = redisClient.invoke(jedisPool, jedis -> { byte[] result = jedis.lpop(key.getBytes()); if (result == null) { return null; } return JsonSerializer.deserialize(result, clazz); }); return obj; } /** * 移除并返回列表的最后一个元素 * * @param key * @return 列表的最后一个元素。 当列表不存在时,返回 null */ public <T> T rpop(String key, Class<T> clazz) { validateParam(key, clazz); T obj = redisClient.invoke(jedisPool, jedis -> { byte[] result = jedis.rpop(key.getBytes()); if (result == null) { return null; } return JsonSerializer.deserialize(result, clazz); }); return obj; } /** * -------------------Redis 发布订阅--------------------- */ public Long publish(String key, Object value) { validateParam(key, value); Long len = redisClient.invoke(jedisPool, jedis -> { return jedis.publish(key.getBytes(), JsonSerializer.serialize(value)); }); return len; } /** * -------------------Hash相关操作--------------------- */ /** * 用于为哈希表中的字段赋值 * 如果哈希表不存在,一个新的哈希表被创建并进行 HSET 操作 * 如果字段已经存在于哈希表中,旧值将被覆盖 * * @param key * @param field * @param value 值 */ public Boolean setHash(String key, String field, Object value) { validateKeyParam(key); long result = redisClient.invoke(jedisPool, (jedis) -> jedis.hset(key.getBytes(), field.getBytes(), JsonSerializer.serialize(value))); if (LONG_ZERO.equals(result)) { return false; } return true; } /** * 用于为哈希表中不存在的的字段赋值 * 如果哈希表不存在,一个新的哈希表被创建并进行 HSET 操作 * 如果字段已经存在于哈希表中,操作无效 * 如果 key 不存在,一个新哈希表被创建并执行 HSETNX 命令 * 设置成功,返回 1 。 如果给定字段已经存在且没有操作被执行,返回 0 。 * 注意版本 >= 2.0.0 * * @param key * @param field * @param value 值 * @return 是否成功 */ public Boolean setNxHash(String key, String field, Object value) { validateKeyParam(key); long result = redisClient.invoke(jedisPool, (jedis) -> jedis.hsetnx(key.getBytes(), field.getBytes(), JsonSerializer.serialize(value))); if (LONG_ZERO.equals(result)) { return false; } return true; } /** * 获取存储在哈希表中指定字段的值 * * @param key * @param field * @return 返回给定字段的值。如果给定的字段或 key 不存在时,返回 null */ public <T> T getHash(String key, String field, Class<T> clazz) { validateKeyParam(key); byte[] value = redisClient.invoke(jedisPool, (jedis) -> jedis.hget(key.getBytes(), field.getBytes())); if (value != null) { return JsonSerializer.deserialize(value, clazz); } return null; } /** * 用于删除哈希表 key 中的个指定字段 * * @param key * @param field */ public void delHash(String key, String field) { validateParam(key, field); redisClient.invoke(jedisPool, (jedis) -> jedis.hdel(key.getBytes(), field.getBytes())); } /** * 用于查看哈希表的指定字段是否存在 * * @param key * @param field */ public Boolean hashKeyExists(String key, String field) { validateParam(key, field); return redisClient.invoke(jedisPool, (jedis) -> jedis.hexists(key.getBytes(), field.getBytes())); } /** * 获取在哈希表中指定 key 的所有字段和值 * 在返回值里,紧跟每个字段名(field name)之后是字段的值(value), * 所以返回值的长度是哈希表大小的两倍。 * * @param key * @return 以列表形式返回哈希表的字段及字段值。 若 key 不存在,返回空列表。 */ public <T> Map<String, T> getAllHash(String key, Class<T> clazz) { validateKeyParam(key); return redisClient.invoke(jedisPool, (jedis) -> { Map<byte[], byte[]> map = jedis.hgetAll(key.getBytes()); Map<String, T> resultMap = new HashMap<>(); if (map != null) { for (Map.Entry<byte[], byte[]> item : map.entrySet()) { byte[] newKey = item.getKey(); T newValue = JsonSerializer.deserialize(item.getValue(), clazz); resultMap.put(Arrays.toString(newKey), newValue); } return resultMap; } return null; }); } /** * -------------------以下危险操作 谨慎使用 --------------------- */ /** * 清空所有redis 数据 * 谨慎使用 */ public void clearAll() { LOGGER.error("缓存的clear方法被调用,所有缓存数据都被清除!"); redisClient.invoke(jedisPool, BinaryJedis::flushAll); } /** * 查找所有符合给定模式( pattern)的 key 。 * 谨慎使用(存在性能问题) * 会引发Redis锁,并且增加Redis的CPU占用 * * @param pattern * @return 符合给定模式的 key 列表 (Array)。 */ public List<String> findKeys(String pattern) { Assert.hasText(pattern, "查找规则不能为空"); Charset charset = Charset.forName("UTF-8"); return redisClient.invoke(jedisPool, jedis -> { Set<String> sets = jedis.keys(("*" + pattern + "*")); if (sets != null) { List<String> list = new ArrayList<>(sets.size()); list.addAll(sets); return list; } return null; }); } /** * 校验参数 */ private void validateParam(String key, Object value) { this.validateKeyParam(key); Assert.notNull(value, "value不能为空"); Assert.isInstanceOf(Object.class, value, "value没有实现Object接口,无法序列化"); } /** * 校验参数 */ private void validateKeyParam(String key) { Assert.hasText(key, "key不能为空"); Assert.notNull(jedisPool, "jedis连接初始化失败"); } public synchronized Jedis getRedis() { return jedisPool.getResource(); } public void setJedisPool(JedisPool jedisPool) { this.jedisPool = jedisPool; } }

测试
创建测试类

@SpringBootTest
@RunWith(SpringRunner.class)
public class RedisSimplePutTest {
    private Logger LOGGER = LoggerFactory.getLogger(RedisSimplePutTest.class);
    @Autowired
    private RedisCache redisCache;
    /**
     * 存储字符串
     */
    @Test
    public void testPutString() {
        String key = "test_string_2";
        String value = "string_value";
        LOGGER.info("存储字符串开始 key={} value={}", key, value);
        boolean putFlag = redisCache.put(key, "string_value", 0, TimeUnit.MINUTES);
        LOGGER.info("存储字符串结束 putFlag={}", putFlag);
        String rvalue = redisCache.get(key);
        LOGGER.info("存储字符串-> 查询缓存value={}", rvalue);
    }
    /**
     * 存储自定义对象
     */
    @Test
    public void testPutObject() {
        String key = "test_object_article_2";
        TArticle tArticle =
                new TArticle("1111", "测试文章1", "作者1", 1.0, 1);
        LOGGER.info("存储对象开始 key={} value={}", key, tArticle);
        redisCache.put(key, tArticle);
        LOGGER.info("存储对象结束");
        TArticle value = redisCache.get(key, TArticle.class);
        LOGGER.info("存储对象-> 查询缓存value={}", value);
    }
}

输出结果

存储字符串开始 key=test_string_2 value=string_value
存储字符串结束 putFlag=true
存储字符串-> 查询缓存value=string_value

存储对象开始 key=test_object_article_2 value=测试文章1
存储对象结束
存储对象-> 查询缓存value=测试文章1

转载于:https://www.cnblogs.com/mengq0815/p/10596066.html

你可能感兴趣的:(SpringBoot+Redis使用jedis实现了对Redis基本类型操作超全工具类)