
io.jboot.component.redis.impl.JbootRedisImpl Maven / Gradle / Ivy
/**
* Copyright (c) 2015-2017, Michael Yang 杨福海 ([email protected]).
*
* Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.gnu.org/licenses/lgpl-3.0.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jboot.component.redis.impl;
import io.jboot.component.redis.JbootRedisBase;
import io.jboot.component.redis.JbootRedisConfig;
import io.jboot.utils.StringUtils;
import redis.clients.jedis.*;
import java.util.*;
import java.util.Map.Entry;
/**
* 参考: com.jfinal.plugin.redis
* JbootRedis 命令文档: http://redisdoc.com/
*/
public class JbootRedisImpl extends JbootRedisBase {
protected JedisPool jedisPool;
public JbootRedisImpl(JbootRedisConfig config) {
String host = config.getHost();
Integer port = config.getPort();
Integer timeout = config.getTimeout();
String password = config.getPassword();
Integer database = config.getDatabase();
String clientName = config.getClientName();
if (host.contains(":")) {
port = Integer.valueOf(host.split(":")[1]);
}
JedisPoolConfig poolConfig = new JedisPoolConfig();
if (StringUtils.isNotBlank(config.getTestWhileIdle())) {
poolConfig.setTestWhileIdle(config.getTestWhileIdle());
}
if (StringUtils.isNotBlank(config.getTestOnBorrow())) {
poolConfig.setTestOnBorrow(config.getTestOnBorrow());
}
if (StringUtils.isNotBlank(config.getTestOnCreate())) {
poolConfig.setTestOnCreate(config.getTestOnCreate());
}
if (StringUtils.isNotBlank(config.getTestOnReturn())) {
poolConfig.setTestOnReturn(config.getTestOnReturn());
}
if (StringUtils.isNotBlank(config.getMinEvictableIdleTimeMillis())) {
poolConfig.setMinEvictableIdleTimeMillis(config.getMinEvictableIdleTimeMillis());
}
if (StringUtils.isNotBlank(config.getTimeBetweenEvictionRunsMillis())) {
poolConfig.setTimeBetweenEvictionRunsMillis(config.getTimeBetweenEvictionRunsMillis());
}
if (StringUtils.isNotBlank(config.getNumTestsPerEvictionRun())) {
poolConfig.setNumTestsPerEvictionRun(config.getNumTestsPerEvictionRun());
}
this.jedisPool = newJedisPool(poolConfig, host, port, timeout, password, database, clientName);
}
public static JedisPool newJedisPool(JedisPoolConfig jedisPoolConfig, String host, Integer port, Integer timeout, String password, Integer database, String clientName) {
JedisPool jedisPool;
if (port != null && timeout != null && password != null && database != null && clientName != null)
jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout, password, database, clientName);
else if (port != null && timeout != null && password != null && database != null)
jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout, password, database);
else if (port != null && timeout != null && password != null)
jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout, password);
else if (port != null && timeout != null)
jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout);
else if (port != null)
jedisPool = new JedisPool(jedisPoolConfig, host, port);
else
jedisPool = new JedisPool(jedisPoolConfig, host);
return jedisPool;
}
public JbootRedisImpl(JedisPool jedisPool) {
this.jedisPool = jedisPool;
}
/**
* 存放 key value 对到 redis
* 如果 key 已经持有其他值, SET 就覆写旧值,无视类型。
* 对于某个原本带有生存时间(TTL)的键来说, 当 SET 命令成功在这个键上执行时, 这个键原有的 TTL 将被清除。
*/
public String set(Object key, Object value) {
Jedis jedis = getJedis();
try {
return jedis.set(keyToBytes(key), valueToBytes(value));
} finally {
returnResource(jedis);
}
}
@Override
public Long setnx(Object key, Object value) {
Jedis jedis = getJedis();
try {
return jedis.setnx(keyToBytes(key), valueToBytes(value));
} finally {
returnResource(jedis);
}
}
/**
* 存放 key value 对到 redis
* 如果 key 已经持有其他值, SET 就覆写旧值,无视类型。
* 此方法用了修改 incr 等的值
*/
public String setWithoutSerialize(Object key, Object value) {
Jedis jedis = getJedis();
try {
return jedis.set(keyToBytes(key), value.toString().getBytes());
} finally {
returnResource(jedis);
}
}
/**
* 存放 key value 对到 redis,并将 key 的生存时间设为 seconds (以秒为单位)。
* 如果 key 已经存在, SETEX 命令将覆写旧值。
*/
public String setex(Object key, int seconds, Object value) {
Jedis jedis = getJedis();
try {
return jedis.setex(keyToBytes(key), seconds, valueToBytes(value));
} finally {
returnResource(jedis);
}
}
/**
* 返回 key 所关联的 value 值
* 如果 key 不存在那么返回特殊值 nil 。
*/
@SuppressWarnings("unchecked")
public T get(Object key) {
Jedis jedis = getJedis();
try {
return (T) valueFromBytes(jedis.get(keyToBytes(key)));
} finally {
returnResource(jedis);
}
}
/**
* 删除给定的一个 key
* 不存在的 key 会被忽略。
*/
public Long del(Object key) {
Jedis jedis = getJedis();
try {
return jedis.del(keyToBytes(key));
} finally {
returnResource(jedis);
}
}
/**
* 删除给定的多个 key
* 不存在的 key 会被忽略。
*/
public Long del(Object... keys) {
Jedis jedis = getJedis();
try {
return jedis.del(keysToBytesArray(keys));
} finally {
returnResource(jedis);
}
}
/**
* 查找所有符合给定模式 pattern 的 key 。
* KEYS * 匹配数据库中所有 key 。
* KEYS h?llo 匹配 hello , hallo 和 hxllo 等。
* KEYS h*llo 匹配 hllo 和 heeeeello 等。
* KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo 。
* 特殊符号用 \ 隔开
*/
public Set keys(String pattern) {
Jedis jedis = getJedis();
try {
return jedis.keys(pattern);
} finally {
returnResource(jedis);
}
}
/**
* 同时设置一个或多个 key-value 对。
* 如果某个给定 key 已经存在,那么 MSET 会用新值覆盖原来的旧值,如果这不是你所希望的效果,请考虑使用 MSETNX 命令:它只会在所有给定 key 都不存在的情况下进行设置操作。
* MSET 是一个原子性(atomic)操作,所有给定 key 都会在同一时间内被设置,某些给定 key 被更新而另一些给定 key 没有改变的情况,不可能发生。
*
* 例子:
* Cache cache = RedisKit.use(); // 使用 JbootRedis 的 cache
* cache.mset("k1", "v1", "k2", "v2"); // 放入多个 key value 键值对
* List list = cache.mget("k1", "k2"); // 利用多个键值得到上面代码放入的值
*
*/
public String mset(Object... keysValues) {
if (keysValues.length % 2 != 0)
throw new IllegalArgumentException("wrong number of arguments for met, keysValues length can not be odd");
Jedis jedis = getJedis();
try {
byte[][] kv = new byte[keysValues.length][];
for (int i = 0; i < keysValues.length; i++) {
if (i % 2 == 0)
kv[i] = keyToBytes(keysValues[i]);
else
kv[i] = valueToBytes(keysValues[i]);
}
return jedis.mset(kv);
} finally {
returnResource(jedis);
}
}
/**
* 返回所有(一个或多个)给定 key 的值。
* 如果给定的 key 里面,有某个 key 不存在,那么这个 key 返回特殊值 nil 。因此,该命令永不失败。
*/
@SuppressWarnings("rawtypes")
public List mget(Object... keys) {
Jedis jedis = getJedis();
try {
byte[][] keysBytesArray = keysToBytesArray(keys);
List data = jedis.mget(keysBytesArray);
return valueListFromBytesList(data);
} finally {
returnResource(jedis);
}
}
/**
* 将 key 中储存的数字值减一。
* 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECR 操作。
* 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
* 本操作的值限制在 64 位(bit)有符号数字表示之内。
* 关于递增(increment) / 递减(decrement)操作的更多信息,请参见 INCR 命令。
*/
public Long decr(Object key) {
Jedis jedis = getJedis();
try {
return jedis.decr(keyToBytes(key));
} finally {
returnResource(jedis);
}
}
/**
* 将 key 所储存的值减去减量 decrement 。
* 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECRBY 操作。
* 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
* 本操作的值限制在 64 位(bit)有符号数字表示之内。
* 关于更多递增(increment) / 递减(decrement)操作的更多信息,请参见 INCR 命令。
*/
public Long decrBy(Object key, long longValue) {
Jedis jedis = getJedis();
try {
return jedis.decrBy(keyToBytes(key), longValue);
} finally {
returnResource(jedis);
}
}
/**
* 将 key 中储存的数字值增一。
* 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。
* 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
* 本操作的值限制在 64 位(bit)有符号数字表示之内。
*/
public Long incr(Object key) {
Jedis jedis = getJedis();
try {
return jedis.incr(keyToBytes(key));
} finally {
returnResource(jedis);
}
}
/**
* 将 key 所储存的值加上增量 increment 。
* 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCRBY 命令。
* 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
* 本操作的值限制在 64 位(bit)有符号数字表示之内。
* 关于递增(increment) / 递减(decrement)操作的更多信息,参见 INCR 命令。
*/
public Long incrBy(Object key, long longValue) {
Jedis jedis = getJedis();
try {
return jedis.incrBy(keyToBytes(key), longValue);
} finally {
returnResource(jedis);
}
}
/**
* 检查给定 key 是否存在。
*/
public boolean exists(Object key) {
Jedis jedis = getJedis();
try {
return jedis.exists(keyToBytes(key));
} finally {
returnResource(jedis);
}
}
/**
* 从当前数据库中随机返回(不删除)一个 key 。
*/
public String randomKey() {
Jedis jedis = getJedis();
try {
return jedis.randomKey();
} finally {
returnResource(jedis);
}
}
/**
* 将 key 改名为 newkey 。
* 当 key 和 newkey 相同,或者 key 不存在时,返回一个错误。
* 当 newkey 已经存在时, RENAME 命令将覆盖旧值。
*/
public String rename(Object oldkey, Object newkey) {
Jedis jedis = getJedis();
try {
return jedis.rename(keyToBytes(oldkey), keyToBytes(newkey));
} finally {
returnResource(jedis);
}
}
/**
* 将当前数据库的 key 移动到给定的数据库 db 当中。
* 如果当前数据库(源数据库)和给定数据库(目标数据库)有相同名字的给定 key ,或者 key 不存在于当前数据库,那么 MOVE 没有任何效果。
* 因此,也可以利用这一特性,将 MOVE 当作锁(locking)原语(primitive)。
*/
public Long move(Object key, int dbIndex) {
Jedis jedis = getJedis();
try {
return jedis.move(keyToBytes(key), dbIndex);
} finally {
returnResource(jedis);
}
}
/**
* 将 key 原子性地从当前实例传送到目标实例的指定数据库上,一旦传送成功, key 保证会出现在目标实例上,而当前实例上的 key 会被删除。
*/
public String migrate(String host, int port, Object key, int destinationDb, int timeout) {
Jedis jedis = getJedis();
try {
return jedis.migrate(valueToBytes(host), port, keyToBytes(key), destinationDb, timeout);
} finally {
returnResource(jedis);
}
}
/**
* 切换到指定的数据库,数据库索引号 index 用数字值指定,以 0 作为起始索引值。
* 默认使用 0 号数据库。
* 注意:在 Jedis 对象被关闭时,数据库又会重新被设置为初始值,所以本方法 select(...)
* 正常工作需要使用如下方式之一:
* 1:使用 RedisInterceptor,在本线程内共享同一个 Jedis 对象
* 2:使用 JbootRedis.call(ICallback) 进行操作
* 3:自行获取 Jedis 对象进行操作
*/
public String select(int databaseIndex) {
Jedis jedis = getJedis();
try {
return jedis.select(databaseIndex);
} finally {
returnResource(jedis);
}
}
/**
* 为给定 key 设置生存时间,当 key 过期时(生存时间为 0 ),它会被自动删除。
* 在 JbootRedis 中,带有生存时间的 key 被称为『易失的』(volatile)。
*/
public Long expire(Object key, int seconds) {
Jedis jedis = getJedis();
try {
return jedis.expire(keyToBytes(key), seconds);
} finally {
returnResource(jedis);
}
}
/**
* EXPIREAT 的作用和 EXPIRE 类似,都用于为 key 设置生存时间。不同在于 EXPIREAT 命令接受的时间参数是 UNIX 时间戳(unix timestamp)。
*/
public Long expireAt(Object key, long unixTime) {
Jedis jedis = getJedis();
try {
return jedis.expireAt(keyToBytes(key), unixTime);
} finally {
returnResource(jedis);
}
}
/**
* 这个命令和 EXPIRE 命令的作用类似,但是它以毫秒为单位设置 key 的生存时间,而不像 EXPIRE 命令那样,以秒为单位。
*/
public Long pexpire(Object key, long milliseconds) {
Jedis jedis = getJedis();
try {
return jedis.pexpire(keyToBytes(key), milliseconds);
} finally {
returnResource(jedis);
}
}
/**
* 这个命令和 EXPIREAT 命令类似,但它以毫秒为单位设置 key 的过期 unix 时间戳,而不是像 EXPIREAT 那样,以秒为单位。
*/
public Long pexpireAt(Object key, long millisecondsTimestamp) {
Jedis jedis = getJedis();
try {
return jedis.pexpireAt(keyToBytes(key), millisecondsTimestamp);
} finally {
returnResource(jedis);
}
}
/**
* 将给定 key 的值设为 value ,并返回 key 的旧值(old value)。
* 当 key 存在但不是字符串类型时,返回一个错误。
*/
@SuppressWarnings("unchecked")
public T getSet(Object key, Object value) {
Jedis jedis = getJedis();
try {
return (T) valueFromBytes(jedis.getSet(keyToBytes(key), valueToBytes(value)));
} finally {
returnResource(jedis);
}
}
/**
* 移除给定 key 的生存时间,将这个 key 从『易失的』(带生存时间 key )转换成『持久的』(一个不带生存时间、永不过期的 key )。
*/
public Long persist(Object key) {
Jedis jedis = getJedis();
try {
return jedis.persist(keyToBytes(key));
} finally {
returnResource(jedis);
}
}
/**
* 返回 key 所储存的值的类型。
*/
public String type(Object key) {
Jedis jedis = getJedis();
try {
return jedis.type(keyToBytes(key));
} finally {
returnResource(jedis);
}
}
/**
* 以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live)。
*/
public Long ttl(Object key) {
Jedis jedis = getJedis();
try {
return jedis.ttl(keyToBytes(key));
} finally {
returnResource(jedis);
}
}
/**
* 这个命令类似于 TTL 命令,但它以毫秒为单位返回 key 的剩余生存时间,而不是像 TTL 命令那样,以秒为单位。
*/
public Long pttl(Object key) {
Jedis jedis = getJedis();
try {
return jedis.pttl(keyToBytes(key));
} finally {
returnResource(jedis);
}
}
/**
* 对象被引用的数量
*/
public Long objectRefcount(Object key) {
Jedis jedis = getJedis();
try {
return jedis.objectRefcount(keyToBytes(key));
} finally {
returnResource(jedis);
}
}
/**
* 对象没有被访问的空闲时间
*/
public Long objectIdletime(Object key) {
Jedis jedis = getJedis();
try {
return jedis.objectIdletime(keyToBytes(key));
} finally {
returnResource(jedis);
}
}
/**
* 将哈希表 key 中的域 field 的值设为 value 。
* 如果 key 不存在,一个新的哈希表被创建并进行 HSET 操作。
* 如果域 field 已经存在于哈希表中,旧值将被覆盖。
*/
public Long hset(Object key, Object field, Object value) {
Jedis jedis = getJedis();
try {
return jedis.hset(keyToBytes(key), valueToBytes(field), valueToBytes(value));
} finally {
returnResource(jedis);
}
}
/**
* 同时将多个 field-value (域-值)对设置到哈希表 key 中。
* 此命令会覆盖哈希表中已存在的域。
* 如果 key 不存在,一个空哈希表被创建并执行 HMSET 操作。
*/
public String hmset(Object key, Map