Redis客户端之Jedis(一)介绍

目录

一、Jedis介绍:

1、背景:

2、Jedis连接池介绍:

二、Jedis API:

1、连接池API

2、其他常用API: 

三、SpringBoot集成Jedis: 

1、Redis集群模式:

(1)配置文件:配置redis、jedis属性信息

(2)Jedis连接池配置类,连接Redis:

(3)Jedis工具类:这里展示基本CRUD操作

2、Redis单机模式:

四、jedis常见应用:

1、Redis五种数据结构基本的增删改查:

2、Redis分布式锁:

(1)加锁:

(2)解锁:

(3)demo:


一、Jedis介绍:
1、背景:

Jedis是基于Java语言的Redis的客户端,Jedis = Java + Redis。Redis不仅可以使用命令来操作,现在基本上主流的语言都有API支持,比如Java、C#、C++、PHP、Node.js、Go等。在官方网站里有一些Java的客户端:Jedis、Redisson、Jredis、JDBC-Redis等,其中官方推荐使用Jedis和Redisson。简言之Jedis是Redis的Java版本API,通过使用Jedis可以操作Redis中的数据。

2、Jedis连接池介绍:

jedis连接资源的创建与销毁是很消耗程序性能,所以jedis为我们提供了jedis的连接池技术,jedis

连接池在创建时初始化一些连接对象存储到连接池中,使用jedis连接资源时不需要自己创建jedis对

象,而是从连接池中获取一个资源进行redis的操作。使用完毕后,不需要销毁该jedis连接资源,

而是将该资源归还给连接池,供其他请求使用。

二、Jedis API:
1、连接池API

JedisPoolConfig配置类

功能说明

JedisPoolConfig()

创建一个配置对象,使用无参构造方法就可以了

void setMaxTotal()

设置连接池最大的连接数

void setMaxWaitMillis()

设置得到连接对象Jedis最长等待时间

JedisPool连接池类

说明

JedisPool(配置对象,服务器名,端口号)

创建连接池

Jedis getResource()

从连接池中得到一个Jedis连接对象

void close()

连接池关闭方法,通常不关闭连接池

2、其他常用API: 

方法

功能

new Jedis(host, port)

创建Jedis的连接,参数:主机名,端口号

set(key,value)

添加一个字符串的键和值

get(key)

得到指定键的值

del(key)

删除指定键和值

hset(key,field,value)

添加一个hash类型的键-字段-值

hget(key,field)

通过hash键-字段得到它的值

lpush(key,values)

从左边添加一个list类型的键和元素

lpop(key)

从左边弹出一个元素

rpop(key)

从右边弹出一个元素

close()

关闭连接

三、SpringBoot集成Jedis: 

pom依赖:加上redis、jedis依赖

 <!-- redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
 
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>

实际应用一般采用Redis集群,这里重点看下集群模式下的集成方式。

1、Redis集群模式:
(1)配置文件:配置redis、jedis属性信息
#redis配置
my.redis.server.jedis.pool.maxTotal=500
my.redis.server.jedis.pool.maxIdle=10
my.redis.server.jedis.pool.maxWaitMillis=5000
my.redis.server.jedis.pool.min-idle=5
my.redis.server.timeout=5000 
#哨兵配置
my.redis.sentinel.nodes=xxx.xx.xxx.111:26379,xxx.xx.xxx.222:26379,xxx.xx.333:26379
my.redis.sentinel.password=wtyy
my.redis.sentinel.master-name=mymaster
my.redis.sentinel.database=10
my.redis.sentinel.pool.max-total=10
my.redis.sentinel.pool.max-idle=5
my.redis.sentinel.pool.min-idle=5
(2)Jedis连接池配置类,连接Redis:
@Configuration
public class JedisConfig {
 
    private Logger logger = LoggerFactory.getLogger(JedisConfig.class);
 
    @Value("${my.redis.server.jedis.pool.maxTotal}")
    private int maxTotal;
 
    @Value("${my.redis.server.jedis.pool.maxIdle}")
    private int maxIdle;
 
    @Value("${my.redis.server.jedis.pool.maxWaitMillis}")
    private int maxWaitMillis;
 
    @Value("${my.redis.server.timeout}")
    private int timeout;
 
    @Value("${my.redis.sentinel.nodes}")
    private String redisSentinelNodes;
 
    @Value("${my.redis.sentinel.pool.max-total}")
    private int redisSentinelMaxTotal;
 
    @Value("${my.redis.sentinel.pool.max-idle}")
    private int redisSentinelMaxIdle;
 
    @Value("${my.redis.sentinel.pool.min-idle}")
    private int redisSentinelMinIdle;
 
    @Value("${my.redis.sentinel.master-name}")
    private String redisSentinelMasterName;
    @Value("${my.redis.sentinel.password}")
    private String redisSentinelPassword;
 
    @Value("${my.redis.sentinel.database}")
    private int dataBase;
 
    @Bean(name = "jedisPool")
    public JedisSentinelPool jedisPool() {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(maxTotal);
        jedisPoolConfig.setMaxIdle(maxIdle);
        jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
        //sentinel
        String[] hosts = redisSentinelNodes.split(",");
        Set<String> sentinels = new HashSet<>(Arrays.asList(hosts));
        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
        poolConfig.setMaxTotal(redisSentinelMaxTotal);
        poolConfig.setMaxIdle(redisSentinelMaxIdle);
        poolConfig.setMinIdle(redisSentinelMinIdle);
       JedisSentinelPool jedisSentinelPool = new JedisSentinelPool(redisSentinelMasterName,
                sentinels, jedisPoolConfig,timeout,redisSentinelPassword,dataBase);
        return  jedisSentinelPool;
    }
}
(3)Jedis工具类:这里展示基本CRUD操作
@SuppressWarnings("unused")
@Component
public class RedisClient {
    private static boolean BORROW = true; // 在borrow一个事例时是否提前进行validate操作
    private static Logger logger = Logger.getLogger(RedisClient.class);
    @Autowired
    private JedisSentinelPool pool;
 
 
    /**
     * 获取连接
     */
    public  synchronized Jedis getJedis() {
        try {
            if (pool != null) {
                return pool.getResource();
            } else {
                return null;
            }
        } catch (Exception e) {
            logger.info("连接池连接异常");
            return null;
        }
 
    }
 
 
 
 
    /**
     * @Description: 关闭连接
     * @param @param jedis
     * @return void 返回类型
     */
    public static void getColse(Jedis jedis) {
        if (jedis != null) {
            jedis.close();
        }
    }
 
 
    /**
     * 格式化Key
     */
    public static String format(String formatKey, String... keyValues) {
        if (keyValues == null || keyValues.length == 0) {
            return formatKey;
        }
        StringBuilder key = new StringBuilder();
        char[] chars = formatKey.toCharArray();
        int index = -1;
        boolean inmark = false;
        boolean firstinmark = false;
        for (int i = 0; i < chars.length; i++) {
            char ch = chars[i];
            if (ch == '{') {
                index++;
                inmark = true;
                firstinmark = true;
            } else if (ch == '}') {
                inmark = false;
            } else if (inmark) {
                if (firstinmark) {
                    firstinmark = false;
                    key.append(keyValues[index]);
                }
            } else {
                key.append(chars[i]);
            }
        }
        return key.toString();
    }
 
    /********************************** 针对key的操作 **************************************/
 
    /**
     * 删除一个key
     *
     * @param keyFormat
     *            key标识
     * @param keyValues
     *            key变量
     * @return 被删除的keys的数量
     */
    public Long del(String keyFormat, String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.del(key);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
 
    /**
     * 查询一个key是否存在
     *
     * @param keyFormat
     *            key标识
     * @param keyValues
     *            key变量
     * @return key是否存在。
     */
    public boolean exists(String keyFormat, String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.exists(key);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
 
    /**
     * 设置一个key的过期的秒数
     *
     * @param keyFormat
     *            key标识
     * @param seconds
     *            过期的秒数
     * @param keyValues
     *            key变量
     * @return 1表示设置成功, 0 表示设置失败或者无法被设置
     */
    public Long expire(String keyFormat, int seconds, String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.expire(key, seconds);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
 
    /**
     * 设置一个UNIX时间戳的过期时间
     *
     * @param keyFormat
     *            key标识
     * @param expireDate
     *            过期时间
     * @param keyValues
     *            key变量
     * @return 1表示设置成功, 0 表示设置失败或者无法被设置
     */
    public Long expireAt(String keyFormat, Date expireDate, String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.pexpireAt(key, expireDate.getTime());
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
 
    /**
     * 移除给定key的生存时间,将这个 key 从『易失的』(带生存时间 key )转换成『持久的』(一个不带生存时间、永不过期的 key )。
     *
     * @param keyFormat
     *            key标识
     * @param keyValues
     *            key变量
     * @return 当生存时间移除成功时,返回 1 . 如果 key 不存在或 key 没有设置生存时间,返回 0 .
     */
    public Long persist(String keyFormat, String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.persist(key);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
 
    /**
     * 设置一个key的过期的毫秒数
     *
     * <pre>
     * 这个命令和 EXPIRE 命令的作用类似,但是它以毫秒为单位设置 key 的生存时间,而不像 EXPIRE 命令那样,以秒为单位。
     * </pre>
     *
     * @param keyFormat
     *            key标识
     * @param milliSeconds
     *            过期的毫秒数
     * @param keyValues
     *            key变量
     * @return 设置成功,返回 1,不存在或设置失败,返回 0
     */
    public Long pexpire(String keyFormat, long milliSeconds,
                        String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.pexpire(key, milliSeconds);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
 
    /**
     * 获取key的有效毫秒数
     *
     * <pre>
     * 这个命令类似于 TTL 命令,但它以毫秒为单位返回 key 的剩余生存时间,而不是像 TTL 命令那样,以秒为单位。
     * </pre>
     *
     * @param keyFormat
     *            key标识
     * @param keyValues
     *            key变量
     * @return 当 key 不存在时,返回 -2 。当 key 存在但没有设置剩余生存时间时,返回 -1 。否则,以毫秒为单位,返回 key
     *         的剩余生存时间。
     */
    public Long pttl(String keyFormat, String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.pttl(key);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
 
 
    /**
     * 获取key的有效时间(单位:秒)
     *
     * <pre>
     * 以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live)。
     * </pre>
     *
     * @param keyFormat
     *            key标识
     * @param keyValues
     *            key变量
     * @return 当 key 不存在时,返回 -2 。当 key 存在但没有设置剩余生存时间时,返回 -1 。否则,以秒为单位,返回 key
     *         的剩余生存时间。
     */
    public Long ttl(String keyFormat, String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.ttl(key);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
 
    /********************************** 针对字符串(string)的操作 **************************************/
 
    /**
     * 追加一个值到key上
     *
     * <pre>
     * 如果 key 已经存在,并且值为字符串,那么这个命令会把 value 追加到原来值(value)的结尾。
     * 如果 key 不存在,那么它将首先创建一个空字符串的key,再执行追加操作,这种情况 APPEND 将类似于 SET 操作。
     * </pre>
     *
     * @param keyFormat
     *            key标识
     * @param value
     *            要追加的值
     * @param keyValues
     *            key变量
     * @return 返回append后字符串值(value)的长度。
     */
    public Long append(String keyFormat, String value, String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.append(key, value);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
 
    /**
     * 整数原子减1
     *
     * <pre>
     * 对key对应的数字做减1操作。如果key不存在,那么在操作之前,这个key对应的值会被置为0。
     * 如果key有一个错误类型的value或者是一个不能表示成数字的字符串,就返回错误。
     * 这个操作最大支持在64位有符号的整型数字。
     * </pre>
     *
     * @param keyFormat
     *            key标识
     * @param keyValues
     *            key变量
     * @return 数字:减小之后的value
     */
    public Long decr(String keyFormat, String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.decr(key);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
 
    /**
     * 原子减指定的整数
     *
     * <pre>
     * 将key对应的数字减decrement。如果key不存在,操作之前,key就会被置为0。
     * 如果key的value类型错误或者是个不能表示成数字的字符串,就返回错误。
     * 这个操作最多支持64位有符号的正型数字。
     * </pre>
     *
     * @param keyFormat
     *            key标识
     * @param integer
     *            要减小的数值
     * @param keyValues
     *            key变量
     * @return 返回一个数字:减少之后的value值。
     */
    public Long decrby(String keyFormat, long integer, String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.decrBy(key, integer);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
 
    /**
     * @param keyFormat
     *            key标识
     * @param keyValues
     *            key变量
     * @return key对应的value,或者null(key不存在时)
     */
    public String get(String keyFormat, String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.get(key);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
 
    /**
     * 设置一个key的value,并获取设置前的值
     *
     * <pre>
     * 自动将key对应到value并且返回原来key对应的value。如果key存在但是对应的value不是字符串,就返回错误。
     * exp:
     * GETSET可以和INCR一起使用实现支持重置的计数功能。
     * 举个例子:每当有事件发生的时候,一段程序都会调用INCR给key mycounter加1,但是有时我们需要获取计数器的值,并且自动将其重置为0。
     * 这可以通过GETSET mycounter "0"来实现:
     * </pre>
     *
     * @param keyFormat
     *            key标识
     * @param value
     *            要设置的值
     * @param keyValues
     *            key变量
     * @return 设置之前的值
     */
    public String getSet(String keyFormat, String value, String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.getSet(key, value);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
 
    /**
     * 执行原子加1操作
     *
     * <pre>
     * 对key对应的数字做加1操作。如果key不存在,那么在操作之前,这个key对应的值会被置为0。
     * 如果key有一个错误类型的value或者是一个不能表示成数字的字符串,就返回错误。这个操作最大支持在64位有符号的整型数字。
     * 提醒:这是一个string操作,因为Redis没有专用的数字类型。key对应的string都被解释成10进制64位有符号的整型来执行这个操作。
     * Redis会用相应的整数表示方法存储整数,所以对于表示数字的字符串,没必要为了用字符串表示整型存储做额外开销。
     * </pre>
     *
     * @param keyFormat
     *            key标识
     * @param keyValues
     *            key变量
     * @return 增加之后的value
     */
    public Long incr(String keyFormat, String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.incr(key);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
 
    /**
     * 执行原子加1操作,并且设置过期时间(单位:s)
     *
     * <pre>
     * 本操作是在{@linkplain RedisClient#incr(String, String...)}之上增加了一个设置过期时间的操作
     * </pre>
     *
     * @param keyFormat
     *            key标识
     * @param expireTime
     *            过期时间(单位:s)
     * @param keyValues
     *            key变量
     * @return 增加之后的value
     */
    public Long incr(String keyFormat, int expireTime, String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            long result = jedis.incr(key);
            jedis.expire(key, expireTime);
            return result;
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
 
    /**
     * 执行原子增加一个整数
     *
     * <pre>
     * 将key对应的数字加increment。如果key不存在,操作之前,key就会被置为0。
     * 如果key的value类型错误或者是个不能表示成数字的字符串,就返回错误。这个操作最多支持64位有符号的正型数字。
     * 查看方法{@linkplain RedisClient#incr(String, String...)}了解关于增减操作的额外信息。
     * </pre>
     *
     * @param keyFormat
     *            key标识
     * @param increment
     *            要增加的数值
     * @param keyValues
     *            key变量
     * @return 增加后的value
     */
    public Long incrBy(String keyFormat, long increment, String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.incrBy(key, increment);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
 
    /**
     * 执行原子增加一个浮点数
     *
     * <pre>
     * 将key对应的数字加increment。如果key不存在,操作之前,key就会被置为0。
     * 如果key的value类型错误或者是个不能表示成数字的字符串,就返回错误。
     * </pre>
     *
     * @param keyFormat
     *            key标识
     * @param increment
     *            要增加的数值
     * @param keyValues
     *            key变量
     * @return 增加后的value
     */
    public Double incrByFloat(String keyFormat, double increment,
                              String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.incrByFloat(key, increment);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
 
    /**
     * 设置一个key的value值
     *
     * <pre>
     * 警告:如果key已经存在了,它会被覆盖,而不管它是什么类型。
     * </pre>
     *
     * @param keyFormat
     *            key标识
     * @param value
     *            要设置的值
     * @param keyValues
     *            key变量
     *
     * @return 总是"OK"
     */
    public String set(String keyFormat, String value, String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.set(key, value);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
 
    /**
     * 设置key-value并设置过期时间(单位:秒)
     *
     * <pre>
     * 设置key对应字符串value,并且设置key在给定的seconds时间之后超时过期。
     * 该命令相当于执行了{@link #set(String, String, String...) SET} + {@link #expire(String, int, String...) EXPIRE}.并且该操作是原子的
     * </pre>
     *
     * @param keyFormat
     *            key标识
     * @param seconds
     *            超时时间(单位:s)
     * @param value
     *            设置的值
     * @param keyValues
     *            key变量
     * @return 状态码
     */
    public String setex(String keyFormat, int seconds, String value,
                        String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.setex(key, seconds, value);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
 
    /**
     * 设置key-value并设置过期时间(单位:毫秒)
     *
     * <pre>
     * 跟{@link #setex(String, int, String, String...)}效果差不多,唯一区别是超时时间是ms
     * </pre>
     *
     * @param keyFormat
     *            key标识
     * @param milliseconds
     *            超时时间(单位:ms)
     * @param value
     *            设置的值
     * @param keyValues
     *            key变量
     * @return 状态码
     */
    public String psetex(String keyFormat, int milliseconds, String value,
                         String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.psetex(key, (long) milliseconds, value);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
 
    /**
     * 设置的一个关键的价值,只有当该键不存在
     *
     * <pre>
     * 如果key不存在,就设置key对应字符串value。在这种情况下,该命令和SET一样。
     * 当key已经存在时,就不做任何操作。SETNX是"SET if Not eXists"。
     * </pre>
     *
     * @param keyFormat
     *            key标识
     * @param value
     *            设置的value
     * @param keyValues
     *            key变量
     * @return 1 如果key被set,0 如果key没有被set
     */
    public Long setnx(String keyFormat, String value, String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.setnx(key, value);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
 
 
    /**
     * 设置hash里面一个字段的值
     *
     * @param keyFormat
     *            key标识
     * @param field
     *            字段
     * @param value
     *            值
     * @param keyValues
     *            key变量
     * @return 含义如下:1如果field是一个新的字段 0如果field原来在map里面已经存在
     *
     */
    public Long hset(String keyFormat, String field, String value,
                     String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.hset(key, field, value);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
 
   
 
    /******************************* SET 操作 *************************/
 
    /**
     * 添加一个元素到集合(set)里
     *
     * <pre>
     * 添加一个指定的member元素到集合的 key中.
     * 如果已经在集合key中存在则忽略.如果集合key 不存在,则新建集合key,并添加member元素到集合key中.
     * 如果key 的类型不是集合则返回错误.
     * </pre>
     *
     * @param keyFormat
     *            key标识
     * @param value
     *            元素
     * @param keyValues
     *            key变量
     * @return 返回新成功添加到集合里元素的数量,不包括已经存在于集合中的元素.
     */
    public Long sadd(String keyFormat, String value, String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.sadd(key, value);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
 
    
 
    /**
     * 获取集合里面的元素数量
     *
     * @param keyFormat
     *            key标识
     * @param keyValues
     *            key变量
     * @return 集合的基数(元素的数量),如果key不存在,则返回 0.
     */
    public Long scard(String keyFormat, String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.scard(key);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
 
    
 
    /**
     * 获取集合里面的所有key
     *
     * @param keyFormat
     *            key标识
     * @param keyValues
     *            key变量
     * @return 集合中的所有元素.
     */
    public Set<String> smembers(String keyFormat, String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.smembers(key);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
 
    /**
     * 删除并获取一个集合里面的元素
     *
     * <pre>
     * 移除并返回一个集合中的随机元素
     * 该命令与 {@link #srandmember(String, String...)}相似,不同的是srandmember命令返回一个随机元素但是不移除.
     * </pre>
     *
     * @param keyFormat
     *            key标识
     * @param keyValues
     *            key变量
     * @return 被移除的元素, 当key不存在的时候返回 null .
     */
    public String spop(String keyFormat, String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.spop(key);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
 
  
    /**
     * 从集合里删除一个元素
     *
     * @param keyFormat
     *            key标识
     * @param member
     *            要删除的元素
     * @param keyValues
     *            key变量
     * @return 从集合中移除元素的个数,不包括不存在的成员.
     */
    public Long srem(String keyFormat, String member, String... keyValues) {
        String key = format(keyFormat, keyValues);
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.srem(key, member);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
    
    /**省略 其他不常用操作**/
 
}
2、Redis单机模式:

配置方式有两种:

(1)代码配置Redis连接:这里省略jedis的一些属性配置

my.redis.server.host=xxx.xx.xxx
my.redis.server.port=6379
my.redis.server.password = wtyy
my.redis.server.jedis.pool.maxTotal=500
my.redis.server.jedis.pool.maxIdle=10
my.redis.server.jedis.pool.maxWaitMillis=5000
my.redis.server.jedis.pool.min-idle=5
my.redis.server.timeout=5000 
@Configuration
public class JedisConfig {
 
    private Logger logger = LoggerFactory.getLogger(JedisConfig.class);
 
    @Value("${my.redis.server.host}")
    private String host;
 
    @Value("${my.redis.server.port}")
    private int port;
 
    @Value("${my.redis.server.password}")
    private String password;
 
    @Value("${my.redis.server.jedis.pool.maxTotal}")
    private int maxTotal;
 
    @Value("${my.redis.server.jedis.pool.maxIdle}")
    private int maxIdle;
 
    @Value("${my.redis.server.jedis.pool.maxWaitMillis}")
    private int maxWaitMillis;
 
    @Value("${my.redis.server.timeout}")
    private int timeout;
 
    @Bean(name = "jedisPool")
    public JedisPool jedisPool() {
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(maxTotal);
        config.setMaxIdle(maxIdle);
        config.setMaxWaitMillis(maxWaitMillis);
        return new JedisPool(config, host, port, timeout,password);
    }
}

(2)在配置文件中配置redis连接:不建议使用

spring.redis.database=1
spring.redis.pool.max-active=8
spring.redis.pool.max-wait=-1
spring.redis.pool.max-idle=500
spring.redis.pool.min-idle=0
spring.redis.timeout=0
四、jedis常见应用:
1、Redis五种数据结构基本的增删改查:

上面的集成demo中,RedisClient演示过了jedis对于Redis的基本CRUD操作,这里不重复。

2、Redis分布式锁:
(1)加锁:
public class RedisTool {
 
    private static final String LOCK_SUCCESS = "OK";
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "PX";
 
    /**
     * 尝试获取分布式锁
     * @param jedis Redis客户端
     * @param lockKey 锁
     * @param requestId 请求标识
     * @param expireTime 超期时间
     * @return 是否获取成功
     */
    public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {
        String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
        if (LOCK_SUCCESS.equals(result)) {
            return true;
        }
        return false;
    }
}
(2)解锁:
public class RedisTool {
 
    private static final Long RELEASE_SUCCESS = 1L;
 
    /**
     * 释放分布式锁
     * @param jedis Redis客户端
     * @param lockKey 锁
     * @param requestId 请求标识
     * @return 是否释放成功
     */
    public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
        if (RELEASE_SUCCESS.equals(result)) {
            return true;
        }
        return false;
    }
}
(3)demo:
/**
*异步导出
*/
public void runTask(ExportRecord record) {
  logger.info("--------导出XXX任务开始 -------------");
  boolean lock = fileExportService.lockTask(record);
        if (!lock) {
            return;
        }
  //...todo...导出业务逻辑
  fileExportService.finishTask(record);
  logger.info("--------导出XXX任务结束 -------------");
}
 
 
FileExportCommonServiceImpl{
    /**
     * redis锁  最长时间  /s
     */
    public static final Integer REDIS_LOCK_DOWNLOAD_MAX_TIME = 60 * 2;
 
    @Override
    public boolean lockTask(ExportRecord record) {
        boolean lock = redisClient.getLock(record.getId(), record.getId(), REDIS_LOCK_DOWNLOAD_MAX_TIME);
        if (!lock) {
            logger.error("获取锁失败,taskId:{}", record.getId());
            return lock;
        }
        //更新record任务状态为进行中
        //todo
        return lock;
    }
 
    @Override
    public boolean finishTask(ExportRecord record) {
        record.setTaskEndTime(new Date());
        //更新task任务结束时间
        //todo
        return redisClient.releaseLock(record.getId(), record.getId());
    }
}
@SuppressWarnings("unused")
@Component
public class RedisClient {

    private  final Logger logger = LoggerFactory.getLogger(RedisClient.class);

    private  final String SUCCESS_OK = "OK";
    private  final Long SUCCESS_STATUS_LONG = 1L;

    // SET IF NOT EXIST,即当key不存在时,我们进行set操作;若key已经存在,则不做任何操作
    private  final String SET_IF_NOT_EXIST = "NX";
    // 给key加一个过期的设置,具体时间由第五个参数决定
    private  final String SET_WITH_EXPIRE_TIME = "PX";
    @Autowired
    private JedisSentinelPool jedisPool;

    public JedisSentinelPool getJedisPool(){
        return jedisPool;
    }

    /**
     * 获取分布式锁
     *
     * @param lockKey
     *            key为锁
     * @param requestId
     *            加锁请求
     * @param expireTime
     *            key的过期时间
     * @return
     */
    public  boolean getLock(String lockKey, String requestId, int expireTime) {
        boolean ret = false;
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            if (jedis == null) {
                return ret;
            }
            String status = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
            if (SUCCESS_OK.equalsIgnoreCase(status)) {
                ret = true;
            }
        } catch (Exception e) {
            logger.error("redis 获取分布式锁 出错", e);
            jedisPool.returnBrokenResource(jedis);
        } finally {
            if (null != jedis) {
                jedisPool.returnResource(jedis);
            }
        }
        return ret;
    }

    /**
     * 释放分布式锁
     *
     * @param lockKey
     * @param requestId
     */
    public  boolean releaseLock(String lockKey, String requestId) {
        boolean ret = false;
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            if (jedis == null) {
                return ret;
            }
			/*
			 * 其他请求误解锁问题 if(requestId.equals(jedis.get(lockKey))) { jedis.del(lockKey); }
			 */

            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
            Object status = jedis.eval(script, Collections.singletonList(lockKey),
                    Collections.singletonList(requestId));
            if (SUCCESS_STATUS_LONG.equals(status)) {
                ret = true;
            }
        } catch (Exception e) {
            logger.error("redis 释放分布式锁 出错", e);
            jedisPool.returnBrokenResource(jedis);
        } finally {
            if (null != jedis) {
                jedisPool.returnResource(jedis);
            }
        }
        return ret;
    }

    /**
     * 序列化存入对象
     *
     * @param key
     * @param obj
     * @return
     */
    public  boolean set(byte[] key, Object obj) {
        boolean ret = false;
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            if (jedis == null) {
                return ret;
            }
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(obj);
            String status = jedis.set(key, baos.toByteArray());
            if (SUCCESS_OK.equalsIgnoreCase(status)) {
                ret = true;
            }
        } catch (Exception e) {
            logger.error("redis set 出错", e);
            jedisPool.returnBrokenResource(jedis);
        } finally {
            if (null != jedis) {
                jedisPool.returnResource(jedis);
            }
        }

        return ret;

    }

    /**
     * 取序列化对象
     *
     * @param key
     * @return
     *//*
    public  Object getObj(byte[] key) {
        Object ret = null;
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            if (jedis == null) {
                return ret;
            }

            byte[] rets = jedis.get(key);
            try{
                ByteArrayInputStream bais = new ByteArrayInputStream(rets);
                ObjectInputStream ois = new ObjectInputStream(bais);
                return ois.readObject();
            }catch (Exception e) {
                logger.error("ObjectInputStream反序列化对象出错", e);
            }
        } catch (Exception e) {
            logger.error("redis get 出错", e);
            jedisPool.returnBrokenResource(jedis);
        } finally {
            if (null != jedis) {
                jedisPool.returnResource(jedis);
            }
        }

        return ret;
    }*/

    /**
     * hash数据类型存储对象
     *
     * @param key
     * @param obj
     * @return
     */
    public  boolean setHm(String key, Object obj) {
        boolean ret = false;
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            if (jedis == null) {
                return ret;
            }
            Map<String, String> hash = objToMap(obj);
            String status = jedis.hmset(key, hash);
            if (SUCCESS_OK.equalsIgnoreCase(status)) {
                ret = true;
            }
        } catch (Exception e) {
            logger.error("redis setHm 出错", e);
            jedisPool.returnBrokenResource(jedis);
        } finally {
            if (null != jedis) {
                jedisPool.returnResource(jedis);
            }
        }

        return ret;
    }

    /**
     * 修改对象属性
     *
     * @param key
     * @param field
     * @param value
     * @return
     */
    public  boolean setHm(String key, String field, String value) {
        boolean ret = false;
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            if (jedis == null) {
                return ret;
            }

            Long status = jedis.hset(key, field, value);
            if (0L == status) {
                ret = true;
            }
        } catch (Exception e) {
            logger.error("redis setHm 出错", e);
            jedisPool.returnBrokenResource(jedis);
        } finally {
            if (null != jedis) {
                jedisPool.returnResource(jedis);
            }
        }

        return ret;
    }

    /**
     * 根据fields 查询key对象属性列表
     *
     * @param key
     * @param fields
     * @return
     */
    public List<String> getHm(String key, String... fields) {
        List<String> ret = null;
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            if (jedis == null) {
                return null;
            }
            ret = jedis.hmget(key, fields);
        } catch (Exception e) {
            logger.error("redis getHm 出错", e);
            jedisPool.returnBrokenResource(jedis);
        } finally {
            if (null != jedis) {
                jedisPool.returnResource(jedis);
            }
        }

        return ret;
    }

    /**
     * 根据fields 查询key对象属性列表
     *
     * @param key
     * @return
     */
    public Long incr(String key) {
        Long count = null;
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            if (jedis == null) {
                return null;
            }
            count = jedis.incr(key);
        } catch (Exception e) {
            logger.error("redis incr 出错", e);
            jedisPool.returnBrokenResource(jedis);
        } finally {
            if (null != jedis) {
                jedisPool.returnResource(jedis);
            }
        }

        return count;
    }

    /**
     * 根据field 查询key对象属性
     *
     * @param key
     * @param
     * @return
     */
    public  String getHm(String key, String field) {
        String ret = null;
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            if (jedis == null) {
                return null;
            }

            ret = jedis.hget(key, field);
        } catch (Exception e) {
            logger.error("redis getHm 出错", e);
            jedisPool.returnBrokenResource(jedis);
        } finally {
            if (null != jedis) {
                jedisPool.returnResource(jedis);
            }
        }

        return ret;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/352468.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MySql8的简单使用(1.模糊查询 2.group by 分组 having过滤 3.JSON字段的实践)

MySql8的简单使用&#xff08;1.模糊查询 2.group by 分组 having过滤 3.JSON字段的实践&#xff09; 一.like模糊查询、group by 分组 having 过滤 建表语句 create table student(id int PRIMARY KEY,name char(10),age int,sex char(5)); alter table student add height…

TCP 状态转换以及半关闭

TCP 状态转换&#xff1a; 上图中还没有进行握手的时候状态是关闭的。 三次握手状态的改变&#xff1a; 客户端发起握手。 调用 connect() 函数时状态转化为&#xff1a;SYN_SENT。调用 listen() 函数时状态转换为&#xff1a;LISTEN。ESTABLISHED是被连接的状态。 四次挥手…

卢禹舜个展开幕作品震撼引人驻足

——“天地人和•大道不孤——卢禹舜中国画作品展”在贵州美术馆盛大开展 1月25日&#xff0c;寒风料峭&#xff0c;冬意正浓&#xff0c;但贵州美术馆大厅内却人潮涌动、热闹非凡。下午3点&#xff0c;由中国国家画院、贵州省文化和旅游厅主办&#xff0c;贵州画院(贵州美术馆…

字符串和C预处理器

本文参考C Primer Plus第四章学习 文章目录 常量和预处理器const限定符 1. 常量和预处理器 有时&#xff0c;在程序中要使用常量。例如&#xff0c;可以这样计算圆的周长&#xff1a; circumference 3.14159 * diameter; 这里&#xff0c;常量3.14159 代表著名的常量 pi(π)。…

详解静态网页数据获取以及浏览器数据和网络数据交互流程

目录 前言 一、静态网页数据 二、网址通讯流程 1.DNS查询 2.建立连接 3.发送HTTP请求 4.服务器处理请求 5.服务器响应 6.渲染页面 7.页面交互 三、URL/POST/GET 1.URL 2.GET 形式 3.POST 形式 四.获取静态网页数据 前言 在网站设计领域&#xff0c;基于纯HTM…

C++中map和set的使用

&#xff08;图片来源于网络&#xff09; &#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;强烈推荐优质专栏: &#x1f354;&#x1f35f;&#x1f32f;C的世界(持续更新中) &#x1f43b;推荐专栏1: &#x1f354;&#x1f35f;&#x1f32f;C语言初阶…

shardinig-JDBC二开-支持sharding-jdbc的配置文件接入到nacos

代码在 https://gitee.com/lbmb/mb-live-app 中 【mb-live-framework】 模块里面的【mb-live-framework-datasource-stater】 如果喜欢 希望大家给给star 项目还在持续更新中。 背景介绍&#xff1a; 因为近期在自己写一套直播项目。使用到了sharding-jdbc来做分库分表的组件…

Python第三方扩展库NumPy

Python第三方扩展库NumPy NumPy(Numerical Python&#xff0c;注意使用时全部小写 numpy) 是 Python 语言的一个扩展程序库&#xff0c;支持大量的维度数组与矩阵运算&#xff0c;此外也针对数组运算提供大量的数学函数库。 在Windows平台上安装numpy&#xff0c;可在cmd命令…

游戏设计模式

单列模式 概念 单例模式是一种创建型设计模式&#xff0c;可以保证一个类只有一个实例&#xff0c;并提供一个访问该实例的全局节点。 优点 可以派生&#xff1a;在单例类的实例构造函数中可以设置以允许子类派生。受控访问&#xff1a;因为单例类封装他的唯一实例&#xf…

学习笔记-李沐动手学深度学习(五)(14-15,数值稳定性、模型初始化和激活函数、Kaggle房价预测)

总结 14-数值稳定性&#xff08;梯度爆炸、梯度消失&#xff09; 尤其是对于深度神经网络&#xff08;即神经网络层数很多&#xff09;&#xff0c;最终的梯度就是每层进行累乘 理论 t&#xff1a;为第t层 y&#xff1a;不是之前的预测值&#xff0c;而是包括了损失函数L …

统一聚合支付系统一个支付系统包含微信支付宝支付接口可对外提供多个网站使用同一个支付系统的初探与逻辑图

#聚合支付# #小李子9479# 开发背景 作为一个合格的站长或者运营&#xff0c;基本上都有好几个网站&#xff0c;而变现的方式其中之一就是付费。经常使用的付费包含微信支付和支付宝支付。微信的jsapi支付需要使用到openid&#xff0c;而获取openid需要设置授权域名&#xff…

C#用TimeSpan的Days、Hours、Minutes及Seconds属性确定程序的运行时间

目录 一、TimeSpan结构的Days、Hours、Minutes及Seconds属性 1.Days属性 2.Hours属性 3.Minutes属性 4.Seconds属性 二、确定程序运行时间的方法 1.实例源码 2.生成效果 在程序设计过程中&#xff0c;经常需要在主窗体中动态地显示程序的运行时间。 一、TimeSpan结构的…

【Linux】-同步互斥的另一种办法-信号量

&#x1f496;作者&#xff1a;小树苗渴望变成参天大树&#x1f388; &#x1f389;作者宣言&#xff1a;认真写好每一篇博客&#x1f4a4; &#x1f38a;作者gitee:gitee✨ &#x1f49e;作者专栏&#xff1a;C语言,数据结构初阶,Linux,C 动态规划算法&#x1f384; 如 果 你 …

身份证也可以cisa远程考试

CISA CISM CRISC CGEIT ​只有身份证 ​没有护照 ​没有港澳通行证 ​也可以线上考试

python学习20

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…

object detection的一些pre trained模型(视频可以实现一下)

https://www.youtube.com/watch?v2yQqg_mXuPQ 你的支持是我创作的源泉

CC++内存管理【非常详细,对新手友好】

文章目录 一、程序内存划分1.基础知识2. 堆栈的区别3. 题目练手 二、C语言中动态内存管理方式三、C中动态内存管理方式1. new/delete操作内置类型2. new/delete操作自定义类型 四、operator new和operator delete函数1. 汇编查看编译器底层调用2. 透过源码分析两个全局函数 五、…

老旧小区火灾频发,LoRa无线系统筑牢安全防线

近日&#xff0c;全国各地多个老旧小区火灾事故频发&#xff0c;从安微合肥南二环一老旧小区居民楼起火、上海金山区一小区居民楼火灾&#xff0c;到1月24日江西新余市特大火灾......都造成了不同程度的人员伤亡和财产损失&#xff0c;令人扼腕痛惜&#xff0c;教训十分深刻。 …

浅谈 ts的类型校验 经验分享

经验1&#xff1a; 【input"testVal $event.target.value"】会有一个ts报错&#xff1a;【“$event.target”可能为 “null”。】我们可以使用【input"testVal (<HTMLInputElement>$event.target).value"】解决ts报错<input type"text&quo…

C#-前后端分离连接mysql数据库封装接口

C#是世界上最好的语言 新建项目 如下图所示选择框红的项目 然后新建 文件夹 Common 并新建类文件 名字任意 文件内容如下 因为要连接的是mysql数据库 所以需要安装 MySql.Data.MySqlClient 依赖; using MySql.Data.MySqlClient; using System.Data;namespace WebApplication1.…
最新文章