14.1 Redis入门
14.2 Redis数据模型
14.3 Jedis基础编程的实践案例
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
14.3.1 Jedis操作String字符串
@Test
public void operateString() {
Jedis jedis = new Jedis("localhost", 6379);
//如果返回 pang 代表链接成功
Logger.info("jedis.ping():" + jedis.ping());
//设置key0的值 123456
jedis.set("key0", "123456");
//返回数据类型 string
Logger.info("jedis.type(key0): " + jedis.type("key0"));
//get key
Logger.info("jedis.get(key0): " + jedis.get("key0"));
// key是否存在
Logger.info("jedis.exists(key0):" + jedis.exists("key0"));
//返回key的长度
Logger.info("jedis.strlen(key0): " + jedis.strlen("key0"));
//返回截取字符串, 范围 0,-1 表示截取全部
Logger.info("jedis.getrange(key0): " + jedis.getrange("key0", 0, -1));
//返回截取字符串, 范围 1,4 表示从表示区间[1,4]
Logger.info("jedis.getrange(key0): " + jedis.getrange("key0", 1, 4));
//追加
Logger.info("jedis.append(key0): " + jedis.append("key0", "appendStr"));
Logger.info("jedis.get(key0): " + jedis.get("key0"));
//重命名
jedis.rename("key0", "key0_new");
//判断key 是否存在
Logger.info("jedis.exists(key0): " + jedis.exists("key0"));
//批量插入
jedis.mset("key1", "val1", "key2", "val2", "key3", "100");
//批量取出
Logger.info("jedis.mget(key1,key2,key3): " + jedis.mget("key1", "key2", "key3"));
//删除
Logger.info("jedis.del(key1): " + jedis.del("key1"));
Logger.info("jedis.exists(key1): " + jedis.exists("key1"));
//取出旧值 并set新值
Logger.info("jedis.getSet(key2): " + jedis.getSet("key2", "value3"));
//自增1 要求数值类型
Logger.info("jedis.incr(key3): " + jedis.incr("key3"));
//自增15 要求数值类型
Logger.info("jedis.incrBy(key3): " + jedis.incrBy("key3", 15));
//自减1 要求数值类型
Logger.info("jedis.decr(key3): " + jedis.decr("key3"));
//自减5 要求数值类型
Logger.info("jedis.decrBy(key3): " + jedis.decrBy("key3", 15));
//增加浮点类型
Logger.info("jedis.incrByFloat(key3): " + jedis.incrByFloat("key3", 1.1));
//返回0 只有在key不存在的时候才设置
Logger.info("jedis.setnx(key3): " + jedis.setnx("key3", "existVal"));
Logger.info("jedis.get(key3): " + jedis.get("key3"));// 3.1
//只有key都不存在的时候才设置,这里返回 null
Logger.info("jedis.msetnx(key2,key3): " + jedis.msetnx("key2", "exists1", "key3", "exists2"));
Logger.info("jedis.mget(key2,key3): " + jedis.mget("key2", "key3"));
//设置key 2 秒后失效
jedis.setex("key4", 2, "2 seconds is no Val");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 2 seconds is no Val
Logger.info("jedis.get(key4): " + jedis.get("key4"));
jedis.set("key6", "123456789");
//下标从0开始,从第三位开始,将新值覆盖旧值
jedis.setrange("key6", 3, "abcdefg");
//返回:123abcdefg
Logger.info("jedis.get(key6): " + jedis.get("key6"));
//返回所有匹配的key
Logger.info("jedis.get(key*): " + jedis.keys("key*"));
jedis.close();
}
14.3.2 Jedis操作List列表
@Test
public void operateList() {
Jedis jedis = new Jedis("localhost");
Logger.info("jedis.ping(): " +jedis.ping());
jedis.del("list1");
//从list尾部添加3个元素
jedis.rpush("list1", "zhangsan", "lisi", "wangwu");
//取得类型, list
Logger.info("jedis.type(): " +jedis.type("list1"));
//遍历区间[0,-1],取得全部的元素
Logger.info("jedis.lrange(0,-1): " +jedis.lrange("list1", 0, -1));
//遍历区间[1,2],取得区间的元素
Logger.info("jedis.lrange(1,2): " +jedis.lrange("list1", 1, 2));
//获取list长度
Logger.info("jedis.llen(list1): " +jedis.llen("list1"));
//获取下标为 1 的元素
Logger.info("jedis.lindex(list1,1): " +jedis.lindex("list1", 1));
//左侧弹出元素
Logger.info("jedis.lpop(): " +jedis.lpop("list1"));
//右侧弹出元素
Logger.info("jedis.rpop(): " +jedis.rpop("list1"));
//设置下标为0的元素val
jedis.lset("list1", 0, "lisi2");
//最后,遍历区间[0,-1],取得全部的元素
Logger.info("jedis.lrange(0,-1): " +jedis.lrange("list1", 0, -1));
jedis.close();
}
14.3.3 Jedis操作Hash哈希表
@Test
public void operateHash() {
Jedis jedis = new Jedis("localhost");
jedis.del("config");
//设置hash的 field-value 对
jedis.hset("config", "ip", "127.0.0.1");
//取得hash的 field的关联的value值
Logger.info("jedis.hget(): " + jedis.hget("config", "ip"));
//取得类型:hash
Logger.info("jedis.type(): " + jedis.type("config"));
//批量添加 field-value 对,参数为java map
Map<String, String> configFields = new HashMap<String, String>();
configFields.put("port", "8080");
configFields.put("maxalive", "3600");
configFields.put("weight", "1.0");
//执行批量添加
jedis.hmset("config", configFields);
//批量获取:取得全部 field-value 对,返回 java map
Logger.info("jedis.hgetAll(): " + jedis.hgetAll("config"));
//批量获取:取得部分 field对应的value,返回 java map
Logger.info("jedis.hmget(): " + jedis.hmget("config", "ip", "port"));
//浮点数增加: 类似于String的 incrByFloat
jedis.hincrByFloat("config", "weight", 1.2);
Logger.info("jedis.hget(weight): " + jedis.hget("config", "weight"));
//获取所有的key
Logger.info("jedis.hkeys(config): " + jedis.hkeys("config"));
//获取所有的val
Logger.info("jedis.hvals(config): " + jedis.hvals("config"));
//获取长度
Logger.info("jedis.hlen(): " + jedis.hlen("config"));
//判断field是否存在
Logger.info("jedis.hexists(weight): " + jedis.hexists("config", "weight"));
//删除一个field
jedis.hdel("config", "weight");
Logger.info("jedis.hexists(weight): " + jedis.hexists("config", "weight"));
jedis.close();
}
14.3.4 Jedis操作Set集合
@Test
public void operateSet() {
Jedis jedis = new Jedis("localhost");
jedis.del("set1");
Logger.info("jedis.ping(): " + jedis.ping());
Logger.info("jedis.type(): " + jedis.type("set1"));
//sadd函数: 向集合添加元素
jedis.sadd("set1", "user01", "user02", "user03");
//smembers函数: 遍历所有元素
Logger.info("jedis.smembers(): " + jedis.smembers("set1"));
//scard函数: 获取集合元素个数
Logger.info("jedis.scard(): " + jedis.scard("set1"));
//sismember 判断是否是集合元素
Logger.info("jedis.sismember(user04): " + jedis.sismember("set1", "user04"));
//srem函数:移除元素
Logger.info("jedis.srem(): " + jedis.srem("set1", "user02", "user01"));
//smembers函数: 遍历所有元素
Logger.info("jedis.smembers(): " + jedis.smembers("set1"));
jedis.close();
}
14.3.5 Jedis操作Zset有序集合
@Test
public void operateZset() {
Jedis jedis = new Jedis("localhost");
Logger.info("jedis.get(): " + jedis.ping());
jedis.del("salary");
Map<String, Double> members = new HashMap<String, Double>();
members.put("u01", 1000.0);
members.put("u02", 2000.0);
members.put("u03", 3000.0);
members.put("u04", 13000.0);
members.put("u05", 23000.0);
//批量添加元素
jedis.zadd("salary", members);
//类型,zset
Logger.info("jedis.type(): " + jedis.type("salary"));
//获取集合元素个数
Logger.info("jedis.zcard(): " + jedis.zcard("salary"));
//按照下标[起,止]遍历元素
Logger.info("jedis.zrange(): " + jedis.zrange("salary", 0, -1));
//按照下标[起,止]倒序遍历元素
Logger.info("jedis.zrevrange(): " + jedis.zrevrange("salary", 0, -1));
//按照分数(薪资)[起,止]遍历元素
Logger.info("jedis.zrangeByScore(): " + jedis.zrangeByScore("salary", 1000, 10000));
//按照薪资[起,止]遍历元素,带分数返回
Set<Tuple> res0 = jedis.zrangeByScoreWithScores("salary", 1000, 10000);
for (Tuple temp : res0) {
Logger.info("Tuple.get(): " + temp.getElement() + " -> " + temp.getScore());
}
//按照分数[起,止]倒序遍历元素
Logger.info("jedis.zrevrangeByScore(): " + jedis.zrevrangeByScore("salary", 1000, 4000));
//获取元素[起,止]分数区间的元素数量
Logger.info("jedis.zcount(): " + jedis.zcount("salary", 1000, 4000));
//获取元素score值:薪资
Logger.info("jedis.zscore(): " + jedis.zscore("salary", "u01"));
//获取元素下标
Logger.info("jedis.zrank(u01): " + jedis.zrank("salary", "u01"));
//倒序获取元素下标
Logger.info("jedis.zrevrank(u01): " + jedis.zrevrank("salary", "u01"));
//删除元素
Logger.info("jedis.zrem(): " + jedis.zrem("salary", "u01", "u02"));
//删除元素,通过下标范围
Logger.info("jedis.zremrangeByRank(): " + jedis.zremrangeByRank("salary", 0, 1));
//删除元素,通过分数范围
Logger.info("jedis.zremrangeByScore(): " + jedis.zremrangeByScore("salary", 20000, 30000));
//按照下标[起,止]遍历元素
Logger.info("jedis.zrange(): " + jedis.zrange("salary", 0, -1));
Map<String, Double> members2 = new HashMap<String, Double>();
members2.put("u11", 1136.0);
members2.put("u12", 2212.0);
members2.put("u13", 3324.0);
//批量添加元素
jedis.zadd("salary", members2);
//增加指定分数
Logger.info("jedis.zincrby(10000): " + jedis.zincrby("salary", 10000, "u13"));
//按照下标[起,止]遍历元素
Logger.info("jedis.zrange(): " + jedis.zrange("salary", 0, -1));
jedis.close();
}
14.4 JedisPool连接池的实践案例
14.4.1 JedisPool的配置
(1) maxTotal:资源池中最大的连接数,默认值为8。
(2) maxIdle:资源池允许最大空闲的连接数,默认值为8。
(3) minIdle:资源池确保最少空闲的连接数,默认值为0。
(4) blockWhenExhausted:当资源池用尽后,调用者是否要等待,默认值为true。
(5) maxWaitMillis:当资源池连接用尽后,调用者的最大等待时间(单位为毫秒)
(6) testOnBorrow:向资源池借用连接时,是否做有效性检测(ping命令),如果是无效连接,会被移除,默认值为false,表示不做检测。
(7) testOnReturn:向资源池归还连接时,是否做有效性检测(ping命令),如果是无效连接,会被移除,默认值为false,表示不做检测。
(8) testWhileIdle:如果为true,表示用一个专门的线程对空闲的连接进行有效性的检测扫描,如果连接的有效性检测失败,即表示监测到无效连接,会从资源池中移除。
(9) timeBetweenEvictionRunsMillis:表示两次空闲连接扫描的间隔时间, 默认为30000毫秒,也就是30秒钟。
(10) minEvictableIdleTimeMillis:表示一个Jedis连接至少停留在空闲状态的最短时间,然后才能被空闲连接扫描线程进行有效性检测,默认值为60000毫秒,即60秒。
(11) numTestsPerEvictionRun:表示空闲检测线程每次最多扫描的Jedis连接数,默认值为-1,表示扫描全部的空闲连接。
(12) jmxEnabled:是否开启JMX监控,默认值为true,建议开启。
14.4.2 JedisPool创建和预热
private static JedisPool buildPool() {
if (pool == null) {
long start = System.currentTimeMillis();
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxIdle(MAX_IDLE);
config.setMaxTotal(MAX_TOTAL);
config.setMaxWaitMillis(1000 * 10);
// 在 borrow 一个 jedis 实例时,是否提前进行有效检测操作;
// 如果为 true,则得到的 jedis 实例均是可用的;
config.setTestOnBorrow(true);
pool = new JedisPool(config, "101.132.251.198", 6379, 10000);
long end = System.currentTimeMillis();
Logger.info("buildPool 毫秒数:", end - start);
}
return pool;
}
预热:
public static void hotPool() {
long start = System.currentTimeMillis();
List<Jedis> minIdleJedisList = new ArrayList<>(MAX_IDLE);
Jedis jedis = null;
for (int i = 0; i < MAX_IDLE; i++) {
try {
jedis = pool.getResource();
minIdleJedisList.add(jedis);
jedis.ping();
}catch (Exception e) {
Logger.error(e.getMessage());
}
}
for (int i = 0; i < MAX_IDLE; i++) {
try {
jedis = minIdleJedisList.get(i);
jedis.close();
}catch (Exception e) {
Logger.error(e.getMessage());
}
}
long end = System.currentTimeMillis();
Logger.info("hotPool 毫秒数:", end - start);
}
创建好连接池实例,并且进行预热
static {
buildPool();
hotPool();
}
public synchronized static Jedis getJedis() {
return pool.getResource();
}
14.4.3 JedisPool的使用
@Test
public void testDel() {
Jedis redis = null;
try {
redis = JedisPoolBuilder.getJedis();
long start = System.currentTimeMillis();
redis.del(ZSET_KEY);
long end = System.currentTimeMillis();
log.info("删除 zset1 毫秒数:", end - start);
}finally {
//使用后一定关闭,还给连接池
if (redis != null) {
redis.close();
}
}
}
使用try-with-resources语句,在其隐藏的finally部分自动调用close方法。
@Test
public void testSet() {
testDel();
try (Jedis redis = JedisPoolBuilder.getJedis()){
int loop = 0;
long start = System.currentTimeMillis();
while (loop < NUM) {
redis.zadd(ZSET_KEY, loop, "field-" + loop);
loop++;
}
long end = System.currentTimeMillis();
Logger.info("设置 Zset :", loop, "次, 毫秒数:", end - start);
}
}
14.5 使用spring-data-redis完成CRUD的实践案例
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>${springboot}</version>
</dependency>
14.5.1 CRUD中应用缓存的场景
14.5.3 使用RedisTemplate模板API
(1) ValueOperations字符串类型操作API集合。
(2) ListOperations列表类型操作API集合。
(3) SetOperations集合类型操作API集合。
(4) ZSetOperations有序集合类型API集合。
(5) HashOperations哈希类型操作API集合。
在实际开发中,为了尽可能地减少对特定的第三方库的依赖,减少第三方库的“入侵”性,或者为了在不同的第三方库之间进行方便的切换,一般来说,要对第三方库进行 封装
public class CacheOperationService {
private RedisTemplate redisTemplate;
public void setRedisTemplate(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
// --------------RedisTemplate 基础操作 --------------------
/**
* 取得指定格式的所有的key
*
* @param patens 匹配的表达式
* @return key 的集合
*/
public Set getKeys(Object patens) {
try {
return redisTemplate.keys(patens);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 指定缓存失效时间
*
* @param key 键
* @param time 时间(秒)
* @return
*/
public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据key 获取过期时间
*
* @param key 键 不能为null
* @return 时间(秒) 返回0代表为永久有效
*/
public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* 判断key是否存在
*
* @param key 键
* @return true 存在 false不存在
*/
public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除缓存
*
* @param key 可以传一个值 或多个
* @return 删除的个数
*/
@SuppressWarnings("unchecked")
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete(CollectionUtils.arrayToList(key));
}
}
}
// --------------RedisTemplate 操作 String --------------------
/**
* 普通缓存获取
*
* @param key 键
* @return 值
*/
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
/**
* 普通缓存放入
*
* @param key 键
* @param value 值
* @return true成功 false失败
*/
public boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 普通缓存放入并设置时间
*
* @param key 键
* @param value 值
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
* @return true成功 false 失败
*/
public boolean set(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue()
.set(key, value, time, TimeUnit.SECONDS);
} else {
set(key, value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 递增
*
* @param key 键
* @param delta 自增因子,要增加几(大于0)
* @return 自增的结果
*/
public long incr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("自增因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, delta);
}
/**
* 自减
*
* @param key 键
* @param delta 自减, 要减少几(小于0)
* @return
*/
public long decr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("自减因子必须大于0");
}
return redisTemplate
.opsForValue().increment(key, -delta);
}
// --------------RedisTemplate 操作 Map --------------------
/**
* HashGet
*
* @param key 键 不能为null
* @param field 项 不能为null
* @return 值
*/
public Object hget(String key, String field) {
return redisTemplate.opsForHash().get(key, field);
}
/**
* 获取hashKey对应的所有键值
*
* @param key 键
* @return 对应的多个键值
*/
public Map<Object, Object> hmget(String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* HashSet
*
* @param key 键
* @param map 对应多个键值
* @return true 成功 false 失败
*/
public boolean hmset(String key, Map<String, Object> map) {
try {
redisTemplate.opsForHash().putAll(key, map);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* HashSet 并设置时间
*
* @param key 键
* @param map 对应多个键值
* @param time 时间(秒)
* @return true成功 false失败
*/
public boolean hmset(String key, Map<String, Object> map, long time) {
try {
redisTemplate.opsForHash().putAll(key, map);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param field 项
* @param value 值
* @return true 成功 false失败
*/
public boolean hset(String key, String field, Object value) {
try {
redisTemplate.opsForHash().put(key, field, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param field 项
* @param value 值
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
* @return true 成功 false失败
*/
public boolean hset(String key, String field, Object value, long time) {
try {
redisTemplate.opsForHash().put(key, field, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除hash表中的值
*
* @param key 键 不能为null
* @param field 项 可以使多个 不能为null
*/
public void hdel(String key, Object... field) {
redisTemplate.opsForHash().delete(key, field);
}
/**
* 判断hash表中是否有该项的值
*
* @param key 键 不能为null
* @param field 项 不能为null
* @return true 存在 false不存在
*/
public boolean hHasKey(String key, String field) {
return redisTemplate.opsForHash().hasKey(key, field);
}
/**
* hash自增 如果不存在,就会创建一个 并把新增后的值返回
*
* @param key 键
* @param field 项
* @param by 要增加几(大于0)
* @return
*/
public double hincr(String key, String field, double by) {
return redisTemplate.opsForHash().increment(key, field, by);
}
/**
* hash自减
*
* @param key 键
* @param field 项
* @param by 要减少记(小于0)
* @return
*/
public double hdecr(String key, String field, double by) {
return redisTemplate.opsForHash().increment(key, field, -by);
}
// --------------RedisTemplate 操作 Set --------------------
/**
* 根据key获取Set中的所有值
*
* @param key 键
* @return
*/
public Set<Object> sGet(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 根据value从一个set中查询,是否存在
*
* @param key 键
* @param value 值
* @return true 存在 false不存在
*/
public boolean sHasKey(String key, Object value) {
try {
return redisTemplate.opsForSet().isMember(key, value);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将数据放入set缓存
*
* @param key 键
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSet(String key, Object... values) {
try {
return redisTemplate.opsForSet().add(key, values);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 将set数据放入缓存
*
* @param key 键
* @param time 时间(秒)
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSetAndTime(String key, long time, Object... values) {
try {
Long count = redisTemplate.opsForSet().add(key, values);
if (time > 0)
expire(key, time);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 获取set缓存的长度
*
* @param key 键
* @return
*/
public long sGetSetSize(String key) {
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 移除值为value的
*
* @param key 键
* @param values 值 可以是多个
* @return 移除的个数
*/
public long setRemove(String key, Object... values) {
try {
Long count = redisTemplate.opsForSet().remove(key, values);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
// --------------RedisTemplate 操作list --------------------
/**
* 获取list缓存的内容
*
* @param key 键
* @param start 开始
* @param end 结束 0 到 -1代表所有值
* @return
*/
public List<Object> lGet(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 获取list缓存的长度
*
* @param key 键
* @return
*/
public long lGetListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 通过索引 获取list中的值
*
* @param key 键
* @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
* @return
*/
public Object lGetIndex(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @return
*/
public boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, Object value, long time) {
try {
redisTemplate.opsForList().rightPush(key, value);
if (time > 0)
expire(key, time);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @return
*/
public boolean lSet(String key, List<Object> value) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, List<Object> value, long time) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
if (time > 0)
expire(key, time);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据索引修改list中的某条数据
*
* @param key 键
* @param index 索引
* @param value 值
* @return
*/
public boolean lUpdateIndex(String key, long index, Object value) {
try {
redisTemplate.opsForList().set(key, index, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 移除N个值为value
*
* @param key 键
* @param count 移除多少个
* @param value 值
* @return 移除的个数
*/
public long lRemove(String key, long count, Object value) {
try {
Long remove = redisTemplate.opsForList().remove(key, count, value);
return remove;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
}
redisTemplate提供了5个方法,取得不同类型的命令集合,具体为:
(1) redisTemplate.opsForValue()取得String类型命令API集合。
(2) redisTemplate.opsForList()取得List类型命令API集合。
(3) redisTemplate.opsForSet()取得Set类型命令API集合。
(4) redisTemplate.opsForHash()取得Hash类型命令API集合。
(5) redisTemplate.opsForZSet()取得Zset类型命令API集合
15.5.4 使用Redis Template模板API完成CRUD的实践案例
public class UserServiceImpleWithTemplate implements UserService{
public static final String USER_UID_PREFIX = "user:uid:";
protected CacheOperationService cacheOperationService;
private static final long CASHE_LONG = 60 * 4;
@Override
public User saveUser(User user) {
String key = USER_UID_PREFIX + user.getUid();
Logger.info("user:", user);
cacheOperationService.set(key, user, CASHE_LONG);
return user;
}
@Override
public User getUser(long id) {
String key = USER_UID_PREFIX + id;
User value = (User) cacheOperationService.get(key);
if (null == value) {
return null;
}
return value;
}
@Override
public void deleteUser(long id) {
String key = USER_UID_PREFIX + id;
cacheOperationService.del(key);
Logger.info("delete User: ", id);
}
}
14.5.5 使用RedisCallback回调完成CRUD的实践案例
如果不需要RedisTemplate配置的序列化、反序列化的工具类,或者由于其他的原因,需要直接使用RedisConnection去操作Redis,怎么办呢?可以使用RedisCallback的doInRedis回调方法,在doInRedis回调方法中直接使用实参RedisConnection连接类实例来完成Redis的操作。
14.6 Spring的Redis缓存注解
在Spring中,通过合理的添加缓存注解,也能实现和前面示例程序中一样的缓存功能。
为了方便地提供缓存能力, Spring提供了一组缓存注解。但是,这组注解不仅仅是针对Redis, 这组注解本质上并不是一种具体的缓存实现方案(例如Redis、 EHCache等),而是对缓存使用的统一抽象。通过这组缓存注解,然后加上与具体缓存相匹配的Spring配置,不用编码就可以快速达到缓存的效果。
14.6.1 使用Spring缓存注解完成CRUD的实践案例
@CachePut
作用是设置缓存。先执行方法,并将执行结果缓存起来。@CacheEvict
的作用是删除缓存。在执行方法后,删除缓存。@Cacheable
的作用更多是查询缓存。首先检查注解中的Key键是否在缓存中,如果是,则返回Key的缓存值,不再执行方法;否则,执行方法并将方法结果缓存起来。从后半部分来看,@Cacheable
也具备@CachePut
的能力。
public class UserServiceImplWithAnno implements UserService{
public static final String USER_UID_PREFIX = "'userCache:'+";
@CachePut(key = USER_UID_PREFIX + "T(String).valueOf(#user.uid)")
@Override
public User saveUser(User user) {
Logger.info("user: save to redis");
return user;
}
@Cacheable(key = USER_UID_PREFIX + "T(String).valueOf(#id)")
@Override
public User getUser(long id) {
//如果缓存没有,则从数据库中加载
Logger.info("user: is null");
return null;
}
@CacheEvict(key = USER_UID_PREFIX + "T(String).valueOf(#id)")
@Override
public void deleteUser(long id) {
Logger.info("delete User:", id);
}
}
14.6.3 详解
@CachePut
和@Cacheable
注解@CachePut
负责增加缓存。@Cacheable
负责查询缓存,如果没有查到, 才去执行被注解的方法,并将方法
的结果增加到缓存。14.6.4 详解
@CacheEvict
注解注解@CacheEvict主要用来清除缓存,可以指定的属性有value、 key、 condition、allEntries和beforeInvocation。其中value、 key和condition的语义与@Cacheable对应的属性类似。 value表示清除哪些Cache(对应Cache的空间名称); key表示清除哪个Key键;condition表示清除的条件。
allEntries属性:表示是否全部清空
beforeInvocation属性:表示是否在方法执行前操作缓存
14.6.5 详解
@Caching
组合注解@Caching注解,是一个缓存处理的组合注解。通过@Caching,可以一次指定多个Spring Cache注解的组合。 @Caching注解拥有三个属性:cacheable、 put和evict。
cacheable属性:用于指定一个或者多个@Cacheable注解的组合,可以指定一个,也可以指定多个。
- put属性:用于指定一个或者多个@CachePut注解的组合,可以指定一个,也可以指定多个,用于设置一个或多个key的缓存。
- evict属性:用于指定一个或者多个@CacheEvict注解的组合,可以指定一个,也可以指定多个,用于删除一个或多个key的缓存。
14.7 详解SpringEL(SpEL)
Spring表达式语言全称为“Spring Expression Language”,缩写为“SpEL”。 SpEL提供一种强大、简洁的Spring Bean的动态操作表达式。