本文今天主要是介绍Redis 列表(List)的方法的使用,以及redis对应的Java实现该怎么用。因为篇幅问题,我这里写了一个测试类,引入 RedisTemplate对象,后面例子里就不一一引入了。大家理解就行,如果大家还不知道如何通过Spring Boot 整合redis则可以查看我之前的文章:SpringBoot整合redis(redis支持单节点和集群)
package com.alian.datastruct;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Slf4j
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class RedisListTest {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
}
语法
LPUSH KEY_NAME VALUE1 VALUE2.. VALUEn
RPUSH KEY_NAME VALUE1 VALUE2.. VALUEn
命令操作
127.0.0.1:6379> lpush list1 python
(integer) 1
127.0.0.1:6379> lpush list1 Java
(integer) 2
127.0.0.1:6379> rpush list1 kotlin
(integer) 3
127.0.0.1:6379> lrange list1 0 -1
1) "Java"
2) "python"
3) "kotlin"
需要注意的是,使用LPUSH和RPUSH,如果key不存在,就会自动创建这个key,这里的key就是list1。
Java操作
@Test
public void leftPushAndRightPush() {
String redisKey="list1";
redisTemplate.delete(redisKey);
// 从列表的左边插入
redisTemplate.opsForList().leftPush(redisKey,"Python");
redisTemplate.opsForList().leftPush(redisKey,"Java");
// 从列表的右边插入
redisTemplate.opsForList().rightPush(redisKey,"Kotlin");
// 输出全部列表
List<Object> list = redisTemplate.opsForList().range(redisKey, 0, -1);
log.info("列表的信息:{}", list);
}
列表的信息:[Java, python, kotlin]
语法
LPUSHX KEY_NAME VALUE1 VALUE2.. VALUEn
RPUSHX KEY_NAME VALUE1 VALUE2.. VALUEn
命令操作
127.0.0.1:6379> lpushx list2 java
(integer) 0
127.0.0.1:6379> rpushx list2 javascript
(integer) 0
127.0.0.1:6379> lpush list2 kotlin
(integer) 1
127.0.0.1:6379> lpushx list2 go
(integer) 2
127.0.0.1:6379> rpushx list2 ios
(integer) 3
127.0.0.1:6379> lrange list2 0 -1
1) "go"
2) "kotlin"
3) "ios"
Java操作
@Test
public void leftPushXAndRightPushX() {
redisTemplate.delete(REDIS_KEY);
String redisKey="list2";
// 从列表的左边插入(如果key:list2存在)
redisTemplate.opsForList().leftPushIfPresent(redisKey,"Java");
// 从列表的右边插入(如果key:list2存在)
redisTemplate.opsForList().rightPushIfPresent(redisKey,"Javascript");
// 从列表的左边插入
redisTemplate.opsForList().leftPush(redisKey,"kotlin");
// 从列表的左边插入(如果key:list2存在)
redisTemplate.opsForList().leftPushIfPresent(redisKey,"go");
// 从列表的右边插入(如果key:list2存在)
redisTemplate.opsForList().rightPushIfPresent(redisKey,"ios");
// 输出全部列表
List<Object> list = redisTemplate.opsForList().range(redisKey, 0, -1);
log.info("列表的信息:{}", list);
}
列表的信息:[go, kotlin, ios]
语法
LPOP KEY_NAME
RPOP KEY_NAME
命令操作
127.0.0.1:6379> lpush list3 Python Java Kotlin Go
(integer) 4
127.0.0.1:6379> lpop list3
"Go"
127.0.0.1:6379> rpop list3
"Python"
127.0.0.1:6379> lrange list3 0 -1
1) "Kotlin"
2) "Java"
Java操作
@Test
public void leftPopAndRightPop() {
String redisKey="list3";
redisTemplate.delete(redisKey);
// 给列表list3插入多个数据
redisTemplate.opsForList().leftPushAll(redisKey,"Python","Java","Kotlin","Go");
// 从列表的左边弹出数据
Object leftValue = redisTemplate.opsForList().leftPop(redisKey);
log.info("左边弹出的数据:{}", leftValue);
// 从列表的右边边弹出数据
Object rightValue = redisTemplate.opsForList().rightPop(redisKey);
log.info("右边边弹出的数据:{}", rightValue);
// 输出全部列表
List<Object> list = redisTemplate.opsForList().range(redisKey, 0, -1);
log.info("列表的信息:{}", list);
}
左边弹出的数据:Go
右边边弹出的数据:Python
列表的信息:[Kotlin, Java]
语法
RPOPLPUSH SOURCE_KEY_NAME DESTINATION_KEY_NAME
命令操作
127.0.0.1:6379> rpush list4 Python Java Kotlin Go
(integer) 4
127.0.0.1:6379> rpoplpush list4 anotherList
"Go"
127.0.0.1:6379> lrange list4 0 -1
1) "Python"
2) "Java"
3) "Kotlin"
Java操作
@Test
public void rightPopLeftPush() {
String redisKey = "list4";
redisTemplate.delete(redisKey);
redisTemplate.delete("anotherList");
// 给列表list4插入数据
redisTemplate.opsForList().rightPushAll(redisKey,"Python","Java","Kotlin","Go");
// 从列表的右边弹出一个原素,插入到另外一个列表,
redisTemplate.opsForList().rightPopAndLeftPush(redisKey, "anotherList");
// 输出列表信息
List<Object> list = redisTemplate.opsForList().range(redisKey, 0, -1);
log.info("原列表的信息:{}", list);
// 输出新列表信息
List<Object> anotherList = redisTemplate.opsForList().range("anotherList", 0, -1);
log.info("新列表的信息:{}", anotherList);
}
原列表的信息:[Python, Java, Kotlin]
新列表的信息:[Go]
语法
LLEN KEY_NAME
命令操作
127.0.0.1:6379> rpush list5 Python Java Kotlin Go
(integer) 4
127.0.0.1:6379> llen list5
(integer) 4
127.0.0.1:6379> llen list0
(integer) 0
Java操作
@Test
public void length() {
String redisKey = "list5";
redisTemplate.delete(redisKey);
// 给列表list5插入数据
redisTemplate.opsForList().rightPushAll(redisKey,"Python","Java","Kotlin","Go");
// 获取列表的长度
Long size = redisTemplate.opsForList().size(redisKey);
log.info("列表的长度:{}", size);
}
列表的长度:4
语法
LINDEX KEY_NAME INDEX_POSITION
命令操作
列表从左往右是从 0 开始,列表从右往左是从 -1 开始
127.0.0.1:6379> rpush list6 Python Java Kotlin Go
(integer) 4
127.0.0.1:6379> lindex list6 0
"Python"
127.0.0.1:6379> lindex list6 1
"Java"
127.0.0.1:6379> lindex list6 2
"Kotlin"
127.0.0.1:6379> lindex list6 -1
"Go"
127.0.0.1:6379> lindex list6 -2
"Kotlin"
127.0.0.1:6379> lindex list6 -3
"Java"
Java操作
@Test
public void index() {
String redisKey = "list6";
redisTemplate.delete(redisKey);
// 给列表list6插入数据
redisTemplate.opsForList().rightPushAll(redisKey,"Python","Java","Kotlin","Go");
// 获取列表中索引为【0】的数据
Object value0 = redisTemplate.opsForList().index(redisKey, 0);
log.info("列表中索引为【0】对应的值:{}", value0);
// 获取列表中索引为【1】的数据
Object value1 = redisTemplate.opsForList().index(redisKey, 1);
log.info("列表中索引为【1】对应的值:{}", value1);
// 获取列表中索引为【2】的数据
Object value2 = redisTemplate.opsForList().index(redisKey, 2);
log.info("列表中索引为【2】对应的值:{}", value2);
// 获取列表中索引为【-1】的数据
Object value3 = redisTemplate.opsForList().index(redisKey, -1);
log.info("列表中索引为【-1】对应的值:{}", value3);
// 获取列表中索引为【-2】的数据
Object value4 = redisTemplate.opsForList().index(redisKey, -2);
log.info("列表中索引为【-2】对应的值:{}", value4);
// 获取列表中索引为【-3】的数据
Object value5 = redisTemplate.opsForList().index(redisKey, -3);
log.info("列表中索引为【-3】对应的值:{}", value5);
}
列表中索引为【0】对应的值:Python
列表中索引为【1】对应的值:Java
列表中索引为【2】对应的值:Kotlin
列表中索引为【-1】对应的值:Go
列表中索引为【-2】对应的值:Kotlin
列表中索引为【-3】对应的值:Java
语法
LRANGE KEY_NAME START END
命令操作
返回列表中指定区间内的元素,区间以偏移量 START 和 END 指定。 其中 0 表示列表的第一个元素, 1 表示列表的第二个元素,以此类推。如果是负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推
127.0.0.1:6379> rpush list7 Python Java Kotlin Go Javascript
(integer) 5
127.0.0.1:6379> lrange list7 0 -1
1) "Python"
2) "Java"
3) "Kotlin"
4) "Go"
5) "Javascript"
127.0.0.1:6379> lrange list7 1 3
1) "Java"
2) "Kotlin"
3) "Go"
127.0.0.1:6379> lrange list7 -3 -1
1) "Kotlin"
2) "Go"
3) "Javascript"
Java操作
@Test
public void range() {
String redisKey = "list7";
redisTemplate.delete(redisKey);
// 给列表list7插入数据
redisTemplate.opsForList().rightPushAll(redisKey,"Python","Java","Kotlin","Go","Javascript");
// 获取指定范围的列表数据
List<Object> result1 = redisTemplate.opsForList().range(redisKey, 0, -1);
log.info("列表中索引为【0】到【-1】的列表值:{}", result1);
List<Object> result2 = redisTemplate.opsForList().range(redisKey, 1, 3);
log.info("列表中索引为【1】到【3】的列表值:{}", result2);
List<Object> result3 = redisTemplate.opsForList().range(redisKey, -3, -1);
log.info("列表中索引为【-3】到【-1】的列表值:{}", result3);
}
列表中索引为【0】到【-1】的列表值:[Python, Java, Kotlin, Go, Javascript]
列表中索引为【1】到【3】的列表值:[Java, Kotlin, Go]
列表中索引为【-3】到【-1】的列表值:[Kotlin, Go, Javascript]
语法
LSET KEY_NAME INDEX VALUE
命令操作
127.0.0.1:6379> rpush list8 Python Java Kotlin Go Javascript
(integer) 5
127.0.0.1:6379> lset list8 3 IOS
OK
127.0.0.1:6379> lset list8 4 Android
OK
127.0.0.1:6379> lrange list8 0 -1
1) "Python"
2) "Java"
3) "Kotlin"
4) "IOS"
5) "Android"
Java操作
@Test
public void set() {
String redisKey = "list8";
redisTemplate.delete(redisKey);
// 给列表list8插入数据
redisTemplate.opsForList().rightPushAll(redisKey,"Python","Java","Kotlin","Go","Javascript");
// 把索引3和4分别设置为IOS、Android
redisTemplate.opsForList().set(redisKey, 3, "IOS");
redisTemplate.opsForList().set(redisKey, 4, "Android");
// 获取列表中数据
List<Object> result1 = redisTemplate.opsForList().range(redisKey, 0, -1);
log.info("列表中的数据为:{}", result1);
}
列表中数据为:[Python, Java, Kotlin, IOS, Android]
语法
LINSERT key BEFORE|AFTER pivot value
命令操作
127.0.0.1:6379> rpush list9 Python Java Kotlin
(integer) 3
127.0.0.1:6379> linsert list9 before Java IOS
(integer) 4
127.0.0.1:6379> linsert list9 after Java Android
(integer) 5
127.0.0.1:6379> lrange list9 0 -1
1) "Python"
2) "IOS"
3) "Java"
4) "Android"
5) "Kotlin"
Java操作
@Test
public void insert() {
String redisKey = "list9";
redisTemplate.delete(redisKey);
// 给列表list9插入数据
redisTemplate.opsForList().rightPushAll(redisKey,"Python","Java","Kotlin");
// 在Java前添加IOS
redisTemplate.opsForList().leftPush(redisKey,"Java","IOS");
// 在Java后添加Android
redisTemplate.opsForList().rightPush(redisKey,"Java","Android");
// 获取列表中数据
List<Object> result1 = redisTemplate.opsForList().range(redisKey, 0, -1);
log.info("列表中数据为:{}", result1);
}
列表中数据为:[Python, IOS, Java, Android, Kotlin]
语法
LTRIM KEY_NAME START STOP
命令操作
127.0.0.1:6379> rpush list10 Python Java Kotlin Go Javascript IOS Android
(integer) 7
127.0.0.1:6379> ltrim list10 2 -1
OK
127.0.0.1:6379> lrange list10 0 -1
1) "Kotlin"
2) "Go"
3) "Javascript"
4) "IOS"
5) "Android"
127.0.0.1:6379> ltrim list10 0 -3
OK
127.0.0.1:6379> lrange list10 0 -1
1) "Kotlin"
2) "Go"
3) "Javascript"
127.0.0.1:6379> ltrim list10 1 2
OK
127.0.0.1:6379> lrange list10 0 -1
1) "Go"
2) "Javascript"
Java操作
@Test
public void trim() {
String redisKey = "list10";
redisTemplate.delete(redisKey);
// 给列表list10插入数据
redisTemplate.opsForList().rightPushAll(redisKey,"Python", "Java", "Kotlin", "Go", "Javascript","IOS","Android");
List<Object> result = redisTemplate.opsForList().range(redisKey, 0, -1);
log.info("初始数据为:{}", result);
// 去除头部两个元素
redisTemplate.opsForList().trim(redisKey,2,-1);
// 获取列表中数据
List<Object> result1 = redisTemplate.opsForList().range(redisKey, 0, -1);
log.info("去除头部两个元素后列表中数据为:{}", result1);
// 去除尾部两个元素
redisTemplate.opsForList().trim(redisKey,0,-3);
// 获取列表中数据
List<Object> result2 = redisTemplate.opsForList().range(redisKey, 0, -1);
log.info("去除尾部两个元素后列表中数据为:{}", result2);
// 截取列表中索引从1到2的数据
redisTemplate.opsForList().trim(redisKey, 1, 2);
// 获取列表中数据
List<Object> result3 = redisTemplate.opsForList().range(redisKey, 0, -1);
log.info("截取列表中索引从1到2的数据后:{}", result3);
}
初始数据为:[Python, Java, Kotlin, Go, Javascript, IOS, Android]
去除头部两个元素后列表中数据为:[Kotlin, Go, Javascript, IOS, Android]
去除尾部两个元素后列表中数据为:[Kotlin, Go, Javascript]
截取列表中索引从1到2的数据后:[Go, Javascript]
语法
LREM KEY_NAME count VALUE
命令操作
127.0.0.1:6379> rpush list11 Java Java Kotlin Java Java IOS Java
(integer) 7
127.0.0.1:6379> lrem list11 2 Java
(integer) 2
127.0.0.1:6379> lrange list11 0 -1
1) "Kotlin"
2) "Java"
3) "Java"
4) "IOS"
5) "Java"
127.0.0.1:6379> lrem list11 -1 Java
(integer) 1
127.0.0.1:6379> lrange list11 0 -1
1) "Kotlin"
2) "Java"
3) "Java"
4) "IOS"
127.0.0.1:6379> lrem list11 0 Java
(integer) 2
127.0.0.1:6379> lrange list11 0 -1
1) "Kotlin"
2) "IOS"
@Test
public void count() {
String redisKey = "list11";
redisTemplate.delete(redisKey);
// 给列表list11插入数据
redisTemplate.opsForList().rightPushAll(redisKey, "Java", "Java", "Kotlin", "Java", "Java", "IOS", "Java");
// 从头部开始移除2个Java
redisTemplate.opsForList().remove(redisKey,2,"Java");
// 获取列表中数据
List<Object> result1 = redisTemplate.opsForList().range(redisKey, 0, -1);
log.info("从头部开始移除2个Java值后:{}", result1);
// 从尾部部开始移除1个Java
redisTemplate.opsForList().remove(redisKey,-1,"Java");
// 获取列表中数据
List<Object> result2 = redisTemplate.opsForList().range(redisKey, 0, -1);
log.info("从尾部部开始移除1个Java值后:{}", result2);
// 移除列表中的所有的Java
redisTemplate.opsForList().remove(redisKey,0,"Java");
// 获取列表中数据
List<Object> result3 = redisTemplate.opsForList().range(redisKey, 0, -1);
log.info("移除列表中的所有的Java值后:{}", result3);
}
从头部开始移除2个Java值后:[Kotlin, Java, Java, IOS, Java]
从尾部部开始移除1个Java值后:[Kotlin, Java, Java, IOS]
移除列表中的所有的Java值后:[Kotlin, IOS]
语法
BLPOP LIST1 LIST2 ... LISTn TIMEOUT
BRPOP LIST1 LIST2 ... LISTn TIMEOUT
命令操作
127.0.0.1:6379> rpush list12 Java Python
(integer) 2
127.0.0.1:6379> blpop list12 10
1) "list12"
2) "Java"
127.0.0.1:6379> brpop list12 10
1) "list12"
2) "Python"
127.0.0.1:6379> blpop list12 10
(nil)
(10.01s)
127.0.0.1:6379> brpop list12 10
(nil)
(10.01s)
终端一
127.0.0.1:6379> blpop list12 10
(nil)
(10.05s)
127.0.0.1:6379> blpop list12 10
终端二
127.0.0.1:6379> lpush list12 Scala
(integer) 1
此时终端一会马上得到结果,详细见下图
Java操作
@Test
public void bLeftPopAndBRightPop() {
String redisKey = "list12";
redisTemplate.delete(redisKey);
// 给列表list12插入数据
redisTemplate.opsForList().leftPushAll(redisKey, "Python", "Java");
// 从列表头部弹出元素,超时时间为30秒
Object value1 = redisTemplate.opsForList().leftPop(redisKey, 30, TimeUnit.SECONDS);
log.info("从列表头部阻塞弹出元素:{}", value1);
// 从列表尾部弹出元素,超时时间为30秒
Object value2 = redisTemplate.opsForList().rightPop(redisKey,30, TimeUnit.SECONDS);
log.info("从列表尾部阻塞弹出元素:{}", value2);
try {
// 此时是空列表了,继续头部弹出,此时会阻塞,如果30秒内列表还有元素,就会超时
redisTemplate.opsForList().leftPop(redisKey,30, TimeUnit.SECONDS);
// redisTemplate.opsForList().rightPop(redisKey,30, TimeUnit.SECONDS);
} catch (Exception e) {
log.info("阻塞弹出数据超时");
}
}
从列表头部阻塞弹出元素:Java
从列表尾部阻塞弹出元素:Python
阻塞弹出数据超时
语法
BRPOPLPUSH LIST1 ANOTHER_LIST TIMEOUT
命令操作
127.0.0.1:6379> rpush list13 Java Python
(integer) 2
127.0.0.1:6379> brpoplpush list13 newlist 10
"Python"
127.0.0.1:6379> brpoplpush list13 newlist 10
"Java"
127.0.0.1:6379> brpoplpush list13 newlist 10
(nil)
(10.02s)
127.0.0.1:6379> lrange newlist 0 -1
1) "Java"
2) "Python"
同样的,为了验证阻塞,我们开启另外一个终端,往空列表 list13 写入数据
终端二
127.0.0.1:6379> lpush list13 Scala
(integer) 1
终端一
127.0.0.1:6379> brpoplpush list13 newlist 10
(nil)
(10.05s)
127.0.0.1:6379> brpoplpush list13 newlist 10
"Scala"
(3.57s)
127.0.0.1:6379> lrange newlist 0 -1
1) "Scala"
2) "Java"
3) "Python"
Java操作
@Test
public void bRightPopAndLeftPush() {
String redisKey = "list13";
redisTemplate.delete(redisKey);
// 给列表list13插入数据
redisTemplate.opsForList().leftPushAll(redisKey, "Python", "Java", "Kotlin", "Go");
// 从列表尾部弹出元素,插入到另外一个列表的头部,超时时间为30秒
redisTemplate.opsForList().rightPopAndLeftPush(redisKey,"newList",30, TimeUnit.SECONDS);
}