Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素) ,类似JAVA中的LinkedList
5.1 应用场景
1、对数据量大的集合数据删减
列表数据显示、关注列表、粉丝列表、留言评价等…分页、热点新闻(Top5)等
利用LRANGE还可以很方便的实现分页的功能,在博客系统中,每片博文的评论也可以存入一个单独的list中。
2、任务队列
(list通常用来实现一个消息队列,而且可以确保先后顺序,不必像MySQL那样还需要通过ORDER BY来进行排序)
任务队列介绍(生产者和消费者模式):
在处理Web客户端发送的命令请求时,某些操作的执行时间可能会比我们预期的更长一些,通过将待执行任务的相关信息放入队列里面,并在之后对队列进行处理,用户可以推迟执行那些需要一段时间才能能完成的操作,这种将工作交给任务处理器来执行的做法被称为任务队列(task queue)。
比如:获取最新的评论列表,获取最后登录10个用户,获取最近7天的活跃用户数等或做为队列来使用。
5.2 代码示例
代码:com.javablog.redis.demo.service.impl.ListCacheServiceImpl
package com.javablog.redis.demo.service.impl;
import com.javablog.redis.demo.service.ListCacheService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Service("listCacheService")
public class ListCacheServiceImpl implements ListCacheService {
private final static Logger log = LoggerFactory.getLogger(ListCacheServiceImpl.class);
@Autowired
private RedisTemplate<String, Object> redisTemplate;
/**
* 将list放入缓存
* @param key 键
* @param value 值
* @return true 成功 false 失败
*/
public boolean lpushAll(String key, List <Object> value) {
try {
redisTemplate.opsForList().leftPushAll(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return true 成功 false 失败
*/
public boolean lpushAll(String key, List <Object> value, long time) {
try {
redisTemplate.opsForList().leftPushAll(key, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
* @param key 键
* @param value 值
* @return true 成功 false 失败
*/
public boolean rpushAll(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 true 成功 false 失败
*/
public boolean rpushAll(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;
}
}
/**
* 在变量左边添加元素值。
* @param key 键
* @param object 值
* @return true 成功 false 失败
*/
@Override
public Boolean lpush(String key, Object object) {
try {
redisTemplate.opsForList().leftPush(key, object);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 把最后一个参数值放到指定集合的第一个出现中间参数的前面,如果中间参数值存在的话。
* @param key 键
* @param pivot 中间参数
* @param object 要放的值
* @return 成功 true 失败 false
*/
@Override
public Boolean lpush(String key, Object pivot, Object object) {
try {
redisTemplate.opsForList().leftPush(key,pivot,object);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 集合中第一次出现第二个参数变量元素的右边添加第三个参数变量的元素值。
* @param key 键
* @param pivot 中间参数
* @param object 要放的值
* @return 成功 true 失败 false
*/
@Override
public Boolean rpush(String key, Object pivot,Object object) {
try {
redisTemplate.opsForList().rightPush(key,pivot,object);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向集合最右边添加元素。
* @param key 键
* @param object 值
* @return 成功 true 失败 false
*/
@Override
public Boolean rpush(String key, Object object) {
try {
redisTemplate.opsForList().rightPush(key, object);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 在变量左边添加元素值。
* @param key 键
* @param expireTime 超时时间
* @param objects 值
* @return 成功 true 失败 false
*/
@Override
public Boolean lpush(String key, int expireTime, Object... objects) {
try {
redisTemplate.opsForList().leftPush(key,objects);
if (expireTime > 0) {
expire(key, expireTime);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 在变量右边添加元素值。
* @param key 键
* @param expireTime 超时时间
* @param objects 值
* @return 成功 true 失败 false
*/
@Override
public Boolean rpush(String key, int expireTime, Object... objects) {
try {
redisTemplate.opsForList().rightPush(key,objects);
if (expireTime > 0) {
expire(key, expireTime);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 如果存在集合则向左边添加元素,不存在不加
* @param key 键
* @param object 值
* @return 成功 true 失败 false
*/
public boolean lPushIfPresent(String key, Object object){
try {
redisTemplate.opsForList().leftPushIfPresent(key,object);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 如果存在集合则向右边添加元素,不存在不加
* @param key 键
* @param object 返回
* @return 成功 true 失败 false
*/
public boolean rPushIfPresent(String key, Object object){
try {
redisTemplate.opsForList().rightPushIfPresent(key,object);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 移除集合中的左边第一个元素
* @param key 键
* @return 返回右边的第一个元素
*/
@Override
public Object lpop(String key) {
return redisTemplate.opsForList().leftPop(key);
}
/**
* 移除集合中右边的元素。一般用在队列取值
* @param key 键
* @return 返回右边的元素
*/
@Override
public Object rpop(String key) {
return redisTemplate.opsForList().rightPop(key);
}
/**
* 移除集合中左边的元素在等待的时间里,如果超过等待的时间仍没有元素则退出。一般用在队列取值
* @param key 键
* @param time 时间
* @return 左边的元素
*/
@Override
public Object lpop(String key,long time) {
return redisTemplate.opsForList().leftPop(key,time,TimeUnit.MILLISECONDS);
}
/**
* 移除集合中右边的元素在等待的时间里,如果超过等待的时间仍没有元素则退出。一般用在队列取值
* @param key 键
* @param time 时间
* @return 返回右边元素
*/
@Override
public Object rpop(String key,long time) {
return redisTemplate.opsForList().rightPop(key,time,TimeUnit.MILLISECONDS);
}
/**
*获取指定区间的值。
* @param key 键
* @param start 开始位置
* @param end 结束位置,为-1指结尾的位置, start 0,end -1取所有
* @return
*/
@Override
public List<Object> lrange(String key, long start, long end) {
return redisTemplate.opsForList().range(key,start,end);
}
/**
* 获取集合长度
* @param key 键
* @return 返回长度
*/
@Override
public Long llen(String key) {
return redisTemplate.opsForList().size(key);
}
/**
* 在集合的指定位置插入元素,如果指定位置已有元素,则覆盖,没有则新增,超过集合下标+n则会报错。
* @param key 键
* @param index 位置
* @param value 值
*/
@Override
public void set(String key, Long index, Object value) {
redisTemplate.opsForList().set(key,index,value);
}
/**
* 获取集合指定位置的值
* @param key 键
* @param index 位置
* @return 返回值
*/
@Override
public Object lindex(String key, Long index) {
return redisTemplate.opsForList().index(key,index);
}
/**
* 从存储在键中的列表中删除等于值的元素的第一个计数事件。count> 0:
* 删除等于从左到右移动的值的第一个元素;count< 0:删除等于从右到左移动的值的第一个元素;count = 0:删除等于value的所有元素。
* @param key 键
* @param count
* @param object
* @return
*/
@Override
public long remove(String key,long count,Object object) {
return redisTemplate.opsForList().remove(key, count ,object);
}
/**
* // 截取集合元素长度,保留长度内的数据。
* @param key 键
* @param start 开始位置
* @param end 结束位置
*/
@Override
public void trim(String key,long start,long end) {
redisTemplate.opsForList().trim(key, start, end);
}
/**
* 除集合中右边的元素,同时在左边加入一个元素。
* @param key 键
* @param str 加入的元素
* @return 返回右边的元素
*/
@Override
public Object rightPopAndLeftPush(String key,String str){
return redisTemplate.opsForList().rightPopAndLeftPush(key,str);
}
/**
* 移除集合中右边的元素在等待的时间里,同时在左边添加元素,如果超过等待的时间仍没有元素则退出。
* @param key 键
* @param str 左边增中的值
* @param timeout 超时时间
* @return 返回移除右边的元素
*/
@Override
public Object rightPopAndLeftPush(String key,String str, long timeout){
return redisTemplate.opsForList().rightPopAndLeftPush(key,str,timeout,TimeUnit.MILLISECONDS);
}
/**
* 删除
* @param keys 键
*/
@Override
public void del(String... keys) {
if (keys != null && keys.length > 0) {
if (keys.length == 1) {
redisTemplate.delete(keys[0]);
} else {
redisTemplate.delete(CollectionUtils.arrayToList(keys));
}
}
}
/**
* 设置过期时间
* @param key 键
* @param seconds 超时时间
* @return 成功 true 失败 false
*/
@Override
public boolean expire(String key, long seconds) {
return redisTemplate.expire(key,seconds,TimeUnit.SECONDS);
}
}
5.3 测试用例(老师逐个演示讲解)
代码:com.javablog.redis.demo.ListCacheServiceImplTest
package com.javablog.redis.demo;
import com.javablog.redis.demo.service.ListCacheService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import java.util.ArrayList;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = CacheServiceApplication.class)
@WebAppConfiguration
public class ListCacheServiceImplTest {
private final static Logger log = LoggerFactory.getLogger(ListCacheServiceImplTest.class);
@Autowired
private ListCacheService redisService;
@Test
public void testCacheList(){
//在变量左边添加元素值。
String key ="list" + System.currentTimeMillis();
redisService.lpush(key,"a");
redisService.lpush(key,"b");
redisService.lpush(key,"c");
List<Object> mylist = redisService.lrange(key, 0, -1);
mylist.stream().forEach(System.out::println);
//index 获取集合指定位置的值。
String listValue = (String)redisService.lindex(key,2l) ;
System.out.println("通过index(K key, long index)方法获取指定位置的值:" + listValue);
//获取指定区间的值。
List<Object> list = redisService.lrange(key,0,1);
System.out.println("通过range(K key, long start, long end)方法获取指定范围的集合值:"+list);
// 把最后一个参数,如下:“n”,值放到指定集合的第一个出现中间参数的前面,如果中间参数值存在的话。
redisService.lpush(key,"a","n");
list = redisService.lrange(key,0,-1);
System.out.println("通过leftPush(K key, V pivot, V value)方法把值放到指定参数值前面:" + list);
// 向左边批量添加参数元素
List<Object> list1= new ArrayList<Object>();
list1.add("w");
list1.add("x");
list1.add("y");
redisService.lpushAll(key, list1);
list = redisService.lrange(key,0,-1);
System.out.println("通过leftPushAll(K key, V... values)方法批量添加元素:" + list);
// 如果存在集合则向左边添加元素,不存在不加
redisService.lPushIfPresent(key,"o");
list = redisService.lrange(key,0,-1);
System.out.println("通过leftPushIfPresent(K key, V value)方法向已存在的集合添加元素:" + list);
// 向集合最右边添加元素。
redisService.rpush(key,"w");
list = redisService.lrange(key,0,-1);
System.out.println("通过rightPush(K key, V value)方法向最右边添加元素:" + list);
//向集合中第一次出现第二个参数变量元素的右边添加第三个参数变量的元素值。
redisService.rpush(key,"w","r");
list = redisService.lrange(key,0,-1);
System.out.println("通过rightPush(K key, V pivot, V value)方法向最右边添加元素:" + list);
//向右边批量添加元素rpush
List<Object> list2= new ArrayList<Object>();
list2.add("j");
list2.add("k");
redisService.rpushAll(key,list2);
list = redisService.lrange(key,0,-1);
System.out.println("通过rightPushAll(K key, V... values)方法向最右边批量添加元素:" + list);
// 如果存在集合则向右边添加元素,不存在不加
redisService.rPushIfPresent(key,"d");
list = redisService.lrange(key,0,-1);
System.out.println("通过rightPushIfPresent(K key, V value)方法向已存在的集合添加元素:" + list);
//获取集合长度
long listLength = redisService.llen(key);
System.out.println("通过size(K key)方法获取集合list的长度为:" + listLength);
// 移除集合中的左边第一个元素
Object popValue = redisService.lpop(key);
System.out.print("通过leftPop(K key)方法移除的元素是:" + popValue);
list = redisService.lrange(key,0,-1);
System.out.println(",剩余的元素是:" + list);
// 移除集合中左边的元素在等待的时间里,如果超过等待的时间仍没有元素则退出。一般用在队列取值
popValue = redisService.lpop(key,1000);
System.out.print("通过leftPop(K key, long timeout, TimeUnit unit)方法移除的元素是:" + popValue);
list = redisService.lrange(key,0,-1);
System.out.println(",剩余的元素是:" + list);
// 移除集合中右边的元素。一般用在队列取值
popValue = redisService.rpop(key);
System.out.print("通过rPop(K key)方法移除的元素是:" + popValue);
list = redisService.lrange(key,0,-1);
System.out.println(",剩余的元素是:" + list);
// 移除集合中右边的元素在等待的时间里,如果超过等待的时间仍没有元素则退出。一般用在队列取值
popValue = redisService.rpop(key,1000);
System.out.print("通过leftPop(K key, long timeout, TimeUnit unit)方法移除的元素是:" + popValue);
list = redisService.lrange(key,0,-1);
System.out.println(",剩余的元素是:" + list);
//移除集合中右边的元素,同时在左边加入一个元素。
popValue = redisService.rightPopAndLeftPush(key,"12");
System.out.print("通过rightPopAndLeftPush(K sourceKey, K destinationKey)方法移除的元素是:" + popValue);
list = redisService.lrange(key,0,-1);
System.out.println(",剩余的元素是:" + list);
//移除集合中右边的元素在等待的时间里,同时在左边添加元素,如果超过等待的时间仍没有元素则退出。
popValue = redisService.rightPopAndLeftPush(key,"13",1);
System.out.println("通过rightPopAndLeftPush(K sourceKey, K destinationKey, long timeout)方法移除的元素是:" + popValue);
list = redisService.lrange("presentList",0,-1);
System.out.print(",剩余的元素是:" + list);
// 在集合的指定位置插入元素,如果指定位置已有元素,则覆盖,没有则新增,超过集合下标+n则会报错。
redisService.set(key,3l,"15");
list = redisService.lrange(key,0,-1);
System.out.print("通过set(K key, long index, V value)方法在指定位置添加元素后:" + list);
//从存储在键中的列表中删除等于值的元素的第一个计数事件。count> 0:
//删除等于从左到右移动的值的第一个元素;count< 0:删除等于从右到左移动的值的第一个元素;count = 0:删除等于value的所有元素。
long removeCount = redisService.remove(key,0,"w");
list = redisService.lrange(key,0,-1);
System.out.println("通过remove(K key, long count, Object value)方法移除元素数量:" + removeCount);
System.out.println(",剩余的元素:" + list);
// 截取集合元素长度,保留长度内的数据。
redisService.trim(key,0,5);
list = redisService.lrange(key,0,-1);
System.out.println("通过trim(K key, long start, long end)方法截取后剩余元素:" + list);
//删除
redisService.del(key);
System.out.println("通过del(String... keys) 方法操作后:" + list);
}
}