Redis中间件部署及使用
1. Redis的部署
1.1 CentOS7.x下的直接部署
- 下载源码包
wget http://download.redis.io/releases/redis-4.0.10.tar.gz
- 解压
tar -zxvf redis-4.0.10.tar.gz
- 安装gcc环境
yum install -y gcc
- 进入解压文件夹编译
cd redis-4.0.10
make MALLOC=libc
- 安装redis服务到指定文件夹
make install PREFIX=/usr/local/redis
- 启动redis服务
# 进入redis的bin目录
cd /usr/local/redis/bin
# 直接启动redis服务,使用redis的默认配置
./redis-server
# 通过redis的配置文件进行启动(配置文件在为解压文件夹中的redis.conf)
./redis-server ./redis.conf
- 启动命令行客户端
# 进入redis的bin目录
cd /usr/local/redis/bin
# 启动命令行客户端
./redis-cli
1.2 CentOS7.x下通过Docker的安装部署
- 安装部署命令
docker run -p 6379:6379 -v /usr/local/redis/conf/redis.conf:/etc/redis/redis.conf -v /usr/local/redis/data:/data --name redis-4.0.10 -d redis:4.0.10 redis-server /etc/redis/redis.conf
- 命令说明
# 将容器的6379端口映射到主机的6379端口
-p 6379:6379
# 将主机/usr/local/redis/conf目录下redis.conf挂在到容器/etc/redis/redis.conf
-v /usr/local/redis/conf/redis.conf:/etc/redis/redis.conf
# 将主机 /usr/local/redis/data目录下的data挂载到容器的/data
-v /usr/local/redis/data:/data
- 进入容器启动命令行客户端
# 进入容器
docker exec -it redis-4.0.10 /bin/bash
# 启动命令行客户端
redis-cli
1.3 Redis的配置文件常用配置
- 配置后台运行
# 是否以后台进程运行,默认为no
daemonize yes
- 配置端口
# 监听端口号,默认为6379
port 6379
- 配置外网远程连接
# 绑定地址,默认为本地127.0.0.1
bind 0.0.0.0
- 配置数据库数量
# 数据库数量,编号从0开始(默认使用0号库),默认为16
databases 16
- 配置RDB(快照模式)持久化(默认持久化模式)
# 持久化文件名(必须以.rdb结尾),默认为dump.rdb
dbfilename dump.rdb
# 持久化文件存放的文件夹路径,默认为"./"
dir ./
# 持久化策略
save 900 1 # 在900s(15m)之后,至少有1个key发生变化,则快照
save 300 10 # 在300s(5m)之后,至少有10个key发生变化,则快照
save 60 10000 # 在60s(1m)之后,至少有1000个key发生变化,则快照
- 配置AOF(日志追加模式)持久化
# 是否开启AOF持久化,默认为no
appendonly yes
# AOF持久化日志文件名(必须以.aof结尾),默认为appendonly.aof
appendfilename appendonly.aof
# 持久化文件存放的文件夹路径,默认为"./"
dir ./
# AOF持久化三种同步策略
appendfsync always # 每次有数据发生变化时都会写入appendonly.aof
appendfsync everysec # 默认方式,每秒同步一次到appendonly.aof
appendfsync no # 何时持久化交给操作系统决定进行
2. Redis的使用
2.1 命令行客户端操作指令
2.1.1 操作数据库的指令
- 选择数据库
select 1 # 选择1号数据库
- 清空数据库
# 清空当前数据库
flushdb
# 清空所有数据库
flushall
2.1.2 操作key的指令
- 通过表达式查看key
keys * # 查看所有key
# *表示通配0个或多个, 例如:a*可以匹配a、aa、ab、abb等
# ?表示通配1个,例如:a?可以匹配aa、ab、ac等
# []表示匹配一个[]内包含的任意一个,例如:[abc]可以匹配a、b、c
- 查看key是否存在
exists name # 是否存在key名为name的key
# 返回0表示不存在
# 返回1表示存在
- 删除key
del name # 删除key名为name的key
del name age # 删除key名为name和age的key(可一次删除多个key)
- 设置key的过期时间
expire name 5 # 设置key名为name的key5秒后过期(删除)
pexpire name 5000 # 设置key名为name的key5000毫秒后过期(删除)
# 返回1表示设置成功
- 查看key的过期时间
ttl name # 查看key名为name的key还有多少秒过期
pttl name # 查看key名为name的key还有多少毫秒过期
# 返回-2表示没有key
# 返回-1表示key永久存在(没有过期时间)
- 将key移动到指定数据库
move name 1 # 将key名为name的key移入1号数据库
- 获取一个随机key
randomkey
- 更改key名
rename name name1 # 将key名为name的key改名为name1
- 查看key对应值的类型
type name # 查看key名为name的key对应值的类型
2.1.3 操作String类型的指令
- 设置一个key/value
set name zhangsan # 设置key为name,value为张三
- 获取一个key对应的value
get name # 获取key名为name的key对应的value
- 设置多个key/value
mset name zhangsan age 18 # 设置key为name,value为张三;设置key为age,value为18
- 设置一个key/value,同时设置key的过期时间
setex name 5 zhangsan # 设置key为name,value为张三,过期时间为5秒
psetex name 5000 zhangsan # 设置key为name,value为张三,过期时间为5000毫秒
- 如果key不存在则设置一个key/value
setnx name zhangsan # 如果key名为name的key不存在,则设置key为name,value为张三
- 如果多个key同时不存在则设置多个key/value(只要有一个存在就全不设置)
msetnx name zhangsan age 18 # 如果key名为name和age的key不存在,则设置key为name,value为张三,设置key为age,value为18
- 获取多个key对应的value
mget name age # 获取key名为name的key对应的value;获取key名为age的key对应的value
- 获取一个key的值并设置一个新值
getset name lisi # 获取key名为name的key对应的value,并设置value为lisi
- 获取key对应value的长度
strlen name # 获取key名为name的key对应value的长度
- 追加内容到key对应value的尾部
append name aaa # 追加"aaa"到key名为name的key对应value的尾部
- 获取key对应value的部分内容(下标从0开始)
getrange name 1 3 # 获取key名为name的key对应value下标从1到3的内容
getrange name 1 -1 # 获取key名为name的key对应value下标从1到末尾的内容
- 若key对应value为数值类型,则value加1
incr age # key名为age的key对应value加1
- 若key对应value为数值类型,则value加自定义整数数值
incrby age 10 # key名为age的key对应value加10
- 若key对应value为数值类型,则value减1
decr age # key名为age的key对应value减1
- 若key对应value为数值类型,则value减自定义整数数值
decrby age 10 # key名为age的key对应value减10
- 若key对应value为数值类型,则value加自定义浮点数数值
incrbyfloat score 10.5 # key名为age的key对应value加10.5
2.1.4 操作List类型指令
- 从列表首部添加一个或多个值到key列表中(key列表可以不存在)
lpush name zhangsan lisi wangwu # 从列表首部添加zhangsan、lisi、wangwu到name列表中
- 从列表首部添加一个或多个值到key列表中(key列表必须存在)
lpushx name zhangsan lisi wangwu # 从列表首部添加zhangsan、lisi、wangwu到name列表中
- 从列表尾部添加一个或多个值到key列表中(key列表可以不存在)
rpush name zhangsan lisi wangwu # 从列表尾部添加zhangsan、lisi、wangwu到name列表中
- 从列表尾部添加一个或多个值到key列表中(key列表必须存在)
rpushx name zhangsan lisi wangwu # 从列表尾部添加zhangsan、lisi、wangwu到name列表中
- 返回并移除列表首部的一个元素
lpop name # 返回name列表首元素并移除
- 返回并移除列表尾部的一个元素
rpop name # 返回name列表尾元素并移除
- 获取列表部分元素(下标从0开始)
lrange name 1 3 # 返回name列表下标为1到3的元素
lrange name 1 -1 # 返回name列表下标为1到末尾的元素
- 获取列表的元素个数
llen name # 获取name列表的元素个数
- 设置列表对应下标元素的值(下标必须存在)
lset name 1 lisi # 设置name列表下标为1的值为lisi
- 获取列表指定下标的值
lindex name 1 # 获取name列表下标为1的值
- 从头开始删除列表任意个数的相同值
lrem name 2 zhangsan # 从头开始删除2个值为zhangsan的值
- 保留列表下标区间的元素(下标从0开始)
ltrim name 1 3 # 保留name列表下标从1到3的元素
ltrim name 1 -1 # 保留name列表下标从1到末尾的元素
- 在列表中插入一个元素
linsert name before lisi zhangsan # 在name列表从头开始的第一个lisi前插入zhangsan
linsert name after lisi wangwu # 在name列表从头开始的第一个lisi后插入wangwu
2.1.5 操作Set类型指令
- 向集合中添加元素
sadd name zhangsan lisi wangwu # 添加zhangsan、lisi、wangwu到name集合中
- 获取集合中的所有元素
smembers name # 获取name集合中的所有元素
- 获取集合中元素的个数
scard name # 获取name集合中元素的个数
- 随机获取集合中的元素并移除
spop name # 随机获取name集合中的一个元素并移除
spop name 2 # 随机获取name集合中的两个元素并移除
- 将集合中的一个元素移动到另一个集合中
smove name1 name2 zhangsan # 将name1集合中的zhangsan移动到name2集合中
- 删除集合中的一个或多个元素
srem name zhangsan # 删除name集合中的zhangsan
srem name zhangsan lisi # 删除name集合中的zhangsan和lisi
- 判断集合中是否存在某个元素
sismember name zhangsan # 判断name集合中是否存在zhangsan
- 随机返回集合中的元素
srandmember name # 随机返回name集合中的一个元素
srandmember name 2 # 随机返回name集合中的两个元素
- 获取一个集合相对于其他集合的补集元素
sdiff name1 name2 name3 # 获取name1集合相对于name2集合、name3集合的补集元素
- 获取一个集合相对于其他集合的交集元素
sinter name1 name2 name3 # 获取name1集合相对于name2集合、name3集合的交集元素
- 获取一个集合相对于其他集合的并集
sunion name1 name2 name3 # 获取name1集合相对于name2集合、name3集合的并集元素
2.1.6 操作ZSet类型的指令
- 向有序集合中添加元素
zadd name 10 zhangsan 20 lisi 30 wangwu # 添加zhangsan(10分)、lisi(20分)、wangwu(30分)到name有序集合中
- 获取有序集合的元素个数
zcard name # 获取name有序集合的元素个数
- 获取有序集合部分元素(下标从0开始)
zrange name 1 3 # name有序集合按升序排列并返回下标为1到3的元素
zrange name 1 -1 withscores # name有序集合按升序排列并返回下标为1到末尾的元素以及元素对应的分数
zrevrange name 1 3 # name有序集合按降序排列并返回下标为1到3的元素
zrevrange name 1 -1 withscores # name有序集合按降序排列并返回下标为1到3的元素以及元素对应的分数
zrangebyscore name 0 100 # name有序集合按升序排列并返回元素分数为0到100的元素
zrangebyscore name 0 100 withscores # name有序集合按升序排列并返回元素分数为0到100的元素以及元素对应的分数
zrangebyscore name 0 100 withscores limit 0 2 # name有序集合按升序排列并返回元素分数为0到100的前两个元素以及元素对应的分数
- 获取有序集合某个元素的下标(下标从0开始)
zrank name zhangsan # name有序集合按升序排列并返回zhangsan的下标
zrevrank name zhangsan # name有序集合按降序排列并返回zhangsan的下标
- 获取有序集合某个元素的的分数
zscore name zhangsan # 获取name有序集合zhangsan的分数
- 删除有序集合的一个或多个元素
zrem name zhangsan # 删除name有序集合的zhangsan
zrem name zhangsan lisi # 删除name有序集合的zhangsan和lisi
- 为有序集合的某个元素增加自定义的分数
zincrby name 5 zhangsan # 为name有序集合的zhangsan增加5分
2.1.7 操作Hash类型的指令
- 设置一个key/value
hset person name zhangsan # 设置key为person,value为一个key为name,value为zhangsan的键值对
- 获取key对应value其中一个hashkey对应的值
hget person name # 获取key名为person的key对应value其中一个hashkey为name对应的值
- 同时设置多个key/value
hmset person name zhangsan age 18 # 设置key为person,value为一个key为name,value为zhangsan的键值对和一个key为age,value为18的键值对
- 同时获取key对应value其中多个hashkey对应的值
hmget person name age # 获取key名为person的key对应value中hashkey为name和age对应的值
- 如果key对应value中hashkey不存在则设置一个key/value
hsetnx person name zhangsan # 如果key名为person的key对应value中hashkey为name的hashkey不存在则设置一个hashkey为name,hashvalue为zhangsan的键值对
- 获取key对应value中的所有键值对
hgetall person # 获取key名为person的key对应value所有键值对
- 删除key对应value中的一个或多个hashkey
hdel person name age # 删除key名为person的key对应value中的name和age
- 判断key对应value中的一个hashkey是否存在
hexists person name # 判断key名为person的key对应value中的一个name是否存在
- 获取key对应value中的所有hashkey
hkeys person # 获取key名为person的key对应value中的所有hashkey
- 获取key对应value中的所有hashvalue
hvals person # 获取key名为person的key对应value中的所有hashvalue
- 若key对应value中的hashkey对应hashvalue为数值类型,则hashvalue加自定义整数数值
hincrby person age 2 # key名为person的key对应value中的hashkey为age的hashkey对应的hashvalue加2
- 若key对应value中的hashkey对应hashvalue为数值类型,则hashvalue加自定义浮点数数值
hincrbyfloat person score 1.5 # key名为person的key对应value中的hashkey为score的hashkey对应的hashvalue加1.5
2.2 原生Java操作Redis
- 引入Redis依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
- 操作redis
import redis.clients.jedis.Jedis;
import java.util.Set;
/**
* 测试Redis
*/
public class TestRedis {
public static void main(String[] args) {
// 创建Jedis客户端对象
Jedis jedis = new Jedis("192.168.150.128", 6379);
// 选择数据库(默认使用0号库)
jedis.select(0);
// Redis操作
Set<String> keys = jedis.keys("*");
keys.forEach(System.out::println);
// 释放资源
jedis.close();
}
}
2.3 SpringBoot操作Redis
2.3.1 SpringBoot整合Redis
- 新建SpringBoot项目
- pom.xml依赖
<!--引入Redis依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- application.yml配置
# redis连接配置
spring:
redis:
host: 192.168.150.128
port: 6379
database: 0
- 操作redis
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.util.*;
import java.util.concurrent.TimeUnit;
@SpringBootTest
class SpringbootRedisApplicationTests {
/**
* String类型Redis模板,key和value都为String类型
*/
@Autowired
private StringRedisTemplate stringRedisTemplate;
/**
* 通用类型Redis模板,key和value都为Object类型
*/
@Autowired
private RedisTemplate<Object, Object> redisTemplate;
@Test
void stringRedisTemplateTest() {
/* ************ 操作Key ************ */
// 通过表达式查看key
Set<String> keys = stringRedisTemplate.keys("*");
keys.forEach(System.out::println);
// 查看key是否存在
Boolean hasKey = stringRedisTemplate.hasKey("name");
System.out.println(hasKey);
// 删除key
Boolean delete = stringRedisTemplate.delete("name");
System.out.println(delete);
// 设置过期时间
stringRedisTemplate.expire("name", 5, TimeUnit.SECONDS);
// 查看过期时间
Long expire = stringRedisTemplate.getExpire("name", TimeUnit.SECONDS);
System.out.println(expire);
// 移动key
Boolean move = stringRedisTemplate.move("name", 1);
System.out.println(move);
// 随机获取一个key
String randomKey = stringRedisTemplate.randomKey();
System.out.println(randomKey);
// 更改key名
stringRedisTemplate.rename("name", "newname");
// 查看key类型
DataType type = stringRedisTemplate.type("name");
System.out.println(type);
/* ************ 操作String类型 ************ */
Map<String, String> stringMap = new HashMap<>();
stringMap.put("name", "zhangsan");
stringMap.put("age", "18");
// 添加一个key/value
stringRedisTemplate.opsForValue().set("name", "zhangsan");
// 获取一个key值
String value = stringRedisTemplate.opsForValue().get("name");
System.out.println(value);
// 一次添加多个key/value
stringRedisTemplate.opsForValue().multiSet(stringMap);
// 添加一个key/value,同时设置过期时间
stringRedisTemplate.opsForValue().set("name", "zhangsan", 5, TimeUnit.SECONDS);
// 如果key不存在,添加一个key/value
Boolean setIfAbsent = stringRedisTemplate.opsForValue().setIfAbsent("name", "zhangsan");
System.out.println(setIfAbsent);
// 如果多个key同时不存在则设置多个key/value(只要有一个存在就全不设置)
stringRedisTemplate.opsForValue().multiSetIfAbsent(stringMap);
// 同时获取多个key值
List<String> multiGetValues = stringRedisTemplate.opsForValue().multiGet(Arrays.asList("name", "age"));
multiGetValues.forEach(System.out::println);
// 获取一个key的值并设置一个新值
String oldValue = stringRedisTemplate.opsForValue().getAndSet("name", "lisi");
System.out.println(oldValue);
// 获取key对应value的长度
Long size = stringRedisTemplate.opsForValue().size("name");
System.out.println(size);
// 追加内容到key对应value的尾部
Integer append = stringRedisTemplate.opsForValue().append("name", "aaa");
System.out.println(append);
// 获取key对应value的部分内容(下标从0开始)
String subName1 = stringRedisTemplate.opsForValue().get("name", 1, 3);// 获取key名为name的key对应value下标从1到3的内容
String subName2 = stringRedisTemplate.opsForValue().get("name", 1, -1);// 获取key名为name的key对应value下标从1到末尾的内容
System.out.println(subName1);
System.out.println(subName2);
// 若key对应value为数值类型,则value加1
Long incrementOne = stringRedisTemplate.opsForValue().increment("age");
System.out.println(incrementOne);
// 若key对应value为数值类型,则value加自定义整数数值
Long incrementAny = stringRedisTemplate.opsForValue().increment("age", 2);
System.out.println(incrementAny);
// 若key对应value为数值类型,则value减1
Long decrementOne = stringRedisTemplate.opsForValue().decrement("age");
System.out.println(decrementOne);
// 若key对应value为数值类型,则value减自定义整数数值
Long decrementAny = stringRedisTemplate.opsForValue().decrement("age", 2);
System.out.println(decrementAny);
// 若key对应value为数值类型,则value加自定义浮点数数值
Double incrementDouble = stringRedisTemplate.opsForValue().increment("score", 1.5);
System.out.println(incrementDouble);
/* ************ 操作List类型 ************ */
// 从列表首部添加一个值到key列表中
Long leftPush = stringRedisTemplate.opsForList().leftPush("name", "zhangsan");
System.out.println(leftPush);
// 从列表首部添加多个值到key列表中
Long leftPushAll = stringRedisTemplate.opsForList().leftPushAll("name", "zhangsan", "lisi");
System.out.println(leftPushAll);
// 从列表尾部添加一个值到key列表中
Long rightPush = stringRedisTemplate.opsForList().rightPush("name", "zhangsan");
System.out.println(rightPush);
// 从列表尾部添加多个值到key列表中
Long rightPushAll = stringRedisTemplate.opsForList().rightPush("name", "zhangsan", "lisi");
System.out.println(rightPushAll);
// 返回并移除列表首部的一个元素
String leftPop = stringRedisTemplate.opsForList().leftPop("name");
System.out.println(leftPop);
// 返回并移除列表尾部的一个元素
String rightPop = stringRedisTemplate.opsForList().rightPop("name");
System.out.println(rightPop);
// 获取列表部分元素(下标从0开始)
List<String> range1 = stringRedisTemplate.opsForList().range("name", 0, 1);
List<String> range2 = stringRedisTemplate.opsForList().range("name", 0, -1);
range1.forEach(System.out::println);
range2.forEach(System.out::println);
// 获取列表的元素个数
Long listSize = stringRedisTemplate.opsForList().size("name");
System.out.println(listSize);
// 设置列表对应下标元素的值(下标必须存在)
stringRedisTemplate.opsForList().set("name", 0, "lisi");
// 获取列表指定下标的值
String index = stringRedisTemplate.opsForList().index("name", 0);
System.out.println(index);
// 从头开始删除列表任意个数的相同值
Long remove = stringRedisTemplate.opsForList().remove("name", 2, "zhangsan");
System.out.println(remove);
// 保留列表下标区间的元素(下标从0开始)
stringRedisTemplate.opsForList().trim("name", 1, 3); // 留name列表下标从1到3的元素
stringRedisTemplate.opsForList().trim("name", 1, -1); // 保留name列表下标从1到末尾的元素
// 在列表中某元素前插入一个元素
Long leftInsert = stringRedisTemplate.opsForList().leftPush("name", "lisi", "zhangsan"); // 在name列表从头开始的第一个lisi前插入zhangsan
System.out.println(leftInsert);
// 在列表中某元素后插入一个元素
Long rightInsert = stringRedisTemplate.opsForList().rightPush("name", "lisi", "wangwu"); // 在name列表从头开始的第一个lisi后插入wangwu
System.out.println(rightInsert);
/* ************ 操作Set类型 ************ */
// 向集合中添加一个或多个元素
Long add = stringRedisTemplate.opsForSet().add("name", "zhangsan", "lisi");
System.out.println(add);
// 获取集合中的所有元素
Set<String> members = stringRedisTemplate.opsForSet().members("name");
members.forEach(System.out::println);
// 获取集合中元素的个数
Long sSize = stringRedisTemplate.opsForSet().size("name");
System.out.println(sSize);
// 随机获取集合中的元素并移除
String sPopOne = stringRedisTemplate.opsForSet().pop("name"); // 随机获取name集合中的一个元素并移除
List<String> sPopAny = stringRedisTemplate.opsForSet().pop("name", 2); // 随机获取name集合中的两个元素并移除
System.out.println(sPopOne);
sPopAny.forEach(System.out::println);
// 将集合中的一个元素移动到另一个集合中
Boolean sMove = stringRedisTemplate.opsForSet().move("name1", "zhangsan", "name2"); // 将name1集合中的zhangsan移动到name2集合中
System.out.println(sMove);
// 删除集合中的一个或多个元素
stringRedisTemplate.opsForSet().remove("name", "zhangsan", "lisi");
// 判断集合中是否存在某个元素
Boolean isMember = stringRedisTemplate.opsForSet().isMember("name", "zhangsan");
System.out.println(isMember);
// 随机返回集合中的一个元素
String randomMember = stringRedisTemplate.opsForSet().randomMember("name");
System.out.println(randomMember);
// 随机返回集合中的多个元素
List<String> randomMembers = stringRedisTemplate.opsForSet().randomMembers("name", 2);
randomMembers.forEach(System.out::println);
// 获取一个集合相对于其他集合的补集元素
Set<String> difference = stringRedisTemplate.opsForSet().difference("name1", Arrays.asList("name2", "name3"));
difference.forEach(System.out::println);
// 获取一个集合相对于其他集合的交集元素
Set<String> intersect = stringRedisTemplate.opsForSet().intersect("name1", Arrays.asList("name2", "name3"));
intersect.forEach(System.out::println);
// 获取一个集合相对于其他集合的并集
Set<String> union = stringRedisTemplate.opsForSet().union("name1", Arrays.asList("name2", "name3"));
union.forEach(System.out::println);
/* ************ 操作ZSet类型 ************ */
Set<ZSetOperations.TypedTuple<String>> zSet = new HashSet<>();
zSet.add(new DefaultTypedTuple<>("zhagnsan", 10.0));
zSet.add(new DefaultTypedTuple<>("lisi", 20.0));
// 向有序集合中添加一个元素
Boolean zAddOne = stringRedisTemplate.opsForZSet().add("name", "zhangsan", 10);// 添加zhangsan(10分)到name有序集合中
System.out.println(zAddOne);
// 向有序集合中添加多个元素
Long zAddAny = stringRedisTemplate.opsForZSet().add("name", zSet);
System.out.println(zAddAny);
// 获取有序集合的元素个数
Long zSize = stringRedisTemplate.opsForZSet().size("name");
System.out.println(zSize);
// 获取有序集合部分元素(下标从0开始)
Set<String> zRange1 = stringRedisTemplate.opsForZSet().range("name", 1, 3); // name有序集合按升序排列并返回下标为1到3的元素
zRange1.forEach(System.out::println);
Set<ZSetOperations.TypedTuple<String>> zRang2 = stringRedisTemplate.opsForZSet().rangeWithScores("name", 1, -1); // name有序集合按升序排列并返回下标为1到末尾的元素以及元素对应的分数
zRang2.forEach(typedTuple -> {
System.out.println(typedTuple.getValue());
System.out.println(typedTuple.getScore());
});
Set<String> zRevRange1 = stringRedisTemplate.opsForZSet().reverseRange("name", 1, 3); // name有序集合按降序排列并返回下标为1到3的元素
zRevRange1.forEach(System.out::println);
Set<ZSetOperations.TypedTuple<String>> zRevRange2 = stringRedisTemplate.opsForZSet().reverseRangeWithScores("name", 1, -1); // name有序集合按升序排列并返回下标为1到末尾的元素以及元素对应的分数
zRevRange2.forEach(typedTuple -> {
System.out.println(typedTuple.getValue());
System.out.println(typedTuple.getScore());
});
Set<String> rangeByScore = stringRedisTemplate.opsForZSet().rangeByScore("name", 0, 100); // name有序集合按升序排列并返回元素分数为0到100的元素
rangeByScore.forEach(System.out::println);
Set<ZSetOperations.TypedTuple<String>> rangeByScoreWithScores1 = stringRedisTemplate.opsForZSet().rangeByScoreWithScores("name", 0, 100); // name有序集合按升序排列并返回元素分数为0到100的元素以及元素对应的分数
rangeByScoreWithScores1.forEach(typedTuple -> {
System.out.println(typedTuple.getValue());
System.out.println(typedTuple.getScore());
});
Set<ZSetOperations.TypedTuple<String>> rangeByScoreWithScores2 = stringRedisTemplate.opsForZSet().rangeByScoreWithScores("name", 0, 100, 0, 2); // name有序集合按升序排列并返回元素分数为0到100的前两个元素以及元素对应的分数
rangeByScoreWithScores2.forEach(typedTuple -> {
System.out.println(typedTuple.getValue());
System.out.println(typedTuple.getScore());
});
// 获取有序集合某个元素的下标(下标从0开始)
Long rank = stringRedisTemplate.opsForZSet().rank("name", "zhangsan"); // name有序集合按升序排列并返回zhangsan的下标
System.out.println(rank);
Long reverseRank = stringRedisTemplate.opsForZSet().reverseRank("name", "zhangsan"); // name有序集合按降序排列并返回zhangsan的下标
System.out.println(reverseRank);
// 获取有序集合某个元素的的分数
Double score = stringRedisTemplate.opsForZSet().score("name", "zhangsan");
System.out.println(score);
// 删除有序集合的一个或多个元素
Long zRemove = stringRedisTemplate.opsForZSet().remove("name", "zhangsan", "lisi");
System.out.println(zRemove);
// 为有序集合的某个元素增加自定义的分数
Double incrementScore = stringRedisTemplate.opsForZSet().incrementScore("name", "zhangsan", 5);
System.out.println(incrementScore);
/* ************ 操作Hash类型 ************ */
Map<String, Object> hash = new HashMap<>();
hash.put("name", "zhangsan");
hash.put("age", 18);
// 设置一个key/value
stringRedisTemplate.opsForHash().put("person", "name", "zhangsan");
// 获取key对应value其中一个hashkey对应的值
Object hashValue = stringRedisTemplate.opsForHash().get("person", "name");
System.out.println(hashValue);
// 同时设置多个key/value
stringRedisTemplate.opsForHash().putAll("person", hash);
// 同时获取key对应value其中多个hashkey对应的值
List<Object> multiGet = stringRedisTemplate.opsForHash().multiGet("person", Arrays.asList("name", "age"));
multiGet.forEach(System.out::println);
// 如果key对应value中hashkey不存在则设置一个key/value
Boolean putIfAbsent = stringRedisTemplate.opsForHash().putIfAbsent("person", "name", "zhangsan");
System.out.println(putIfAbsent);
// 获取key对应value中的所有键值对
Map<Object, Object> person = stringRedisTemplate.opsForHash().entries("person");
System.out.println(person);
// 删除key对应value中的一个或多个hashkey
Long hashDelete = stringRedisTemplate.opsForHash().delete("person", "name", "age");
System.out.println(hashDelete);
// 判断key对应value中的一个hashkey是否存在
Boolean hashHasKey = stringRedisTemplate.opsForHash().hasKey("person", "name");
System.out.println(hashHasKey);
// 获取key对应value中的所有hashkey
Set<Object> hashKeys = stringRedisTemplate.opsForHash().keys("person");
hashKeys.forEach(System.out::println);
// 获取key对应value中的所有hashvalue
List<Object> hashValues = stringRedisTemplate.opsForHash().values("person");
hashValues.forEach(System.out::println);
// 若key对应value中的hashkey对应hashvalue为数值类型,则hashvalue加自定义整数数值
Long hashIncrement1 = stringRedisTemplate.opsForHash().increment("person", "age", 2);
System.out.println(hashIncrement1);
// 若key对应value中的hashkey对应hashvalue为数值类型,则hashvalue加自定义浮点数数值
Double hashIncrement2 = stringRedisTemplate.opsForHash().increment("person", "score", 1.5);
System.out.println(hashIncrement2);
}
@Test
void redisTemplateTest() {
// 设置key以String方式序列化
redisTemplate.setKeySerializer(new StringRedisSerializer());
// 设置hashKey以String方式序列化
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
// 以绑定的方式操作key(用于简化书写多次操作同一个key)
BoundValueOperations<Object, Object> boundValueOps = redisTemplate.boundValueOps("name");
boundValueOps.set("zhangsan");
boundValueOps.append("aaa");
/* ************ 操作redis同stringRedisTemplate ************ */
}
}
2.3.2 通过Mybatis的二级缓存实现分布式缓存
- pom.xml依赖
<dependencies>
<!--web依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--redis依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--mysql数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<!--mybatis依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
<!--druid数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.20</version>
</dependency>
<!--lombok依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--测试依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
- application.yml配置
# web端口
server:
port: 8080
spring:
application:
name: rediscache
# redis连接配置
redis:
host: 192.168.150.128
port: 6379
database: 0
# mysql连接配置
datasource:
# 数据库连接
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password:
# 数据源配置
type: com.alibaba.druid.pool.DruidDataSource
# mybatis配置
mybatis:
mapper-locations: classpath*:mapper/**/*.xml
type-aliases-package: com.mo.rediscache.model.entity
# 日志配置
logging:
level:
com.mo.rediscache.mapper: debug
- Spring容器工具类
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* Spring容器工具类
*/
@Component
public class ApplicationContextUtils implements ApplicationContextAware {
/** Spring容器 */
private static ApplicationContext applicationContext;
/**
* Spring容器设置
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ApplicationContextUtils.applicationContext = applicationContext;
}
/**
* 获取Bean
*/
public static Object getBean(String beanName) {
return ApplicationContextUtils.applicationContext.getBean(beanName);
}
}
- 自定义Redis缓存类
import com.mo.rediscache.util.ApplicationContextUtils;
import org.apache.ibatis.cache.Cache;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.DigestUtils;
/**
* Redis缓存
*/
public class RedisCache implements Cache {
/** 缓存命名空间唯一标识 */
private final String id;
/**
* Redis缓存构造方法
*
* @param id 缓存命名空间唯一标识
*/
public RedisCache(String id) {
this.id = id;
}
/**
* 返回缓存命名空间唯一标识
*/
@Override
public String getId() {
return this.id;
}
/**
* 添加缓存
*/
@Override
public void putObject(Object key, Object value) {
this.getRedisTemplate().opsForHash().put(this.id, this.md5Key(key), value);
}
/**
* 获取缓存
*/
@Override
public Object getObject(Object key) {
return this.getRedisTemplate().opsForHash().get(this.id, this.md5Key(key));
}
/**
* 删除缓存(保留方法)
*/
@Override
public Object removeObject(Object key) {
return null;
}
/**
* 清空缓存
*/
@Override
public void clear() {
this.getRedisTemplate().delete(this.id);
}
/**
* 获取缓存数量
*/
@Override
public int getSize() {
return this.getRedisTemplate().opsForHash().size(this.id).intValue();
}
/**
* 获取Redis操作模板对象
*/
private RedisTemplate<String, Object> getRedisTemplate() {
// 获取Redis操作模板对象
RedisTemplate<String, Object> redisTemplate = (RedisTemplate<String, Object>) ApplicationContextUtils.getBean("redisTemplate");
// 设置key以String方式序列化
redisTemplate.setKeySerializer(new StringRedisSerializer());
// 设置hashKey以String方式序列化
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
return redisTemplate;
}
/**
* 获取key的MD5值
*/
private String md5Key(Object key) {
return DigestUtils.md5DigestAsHex(key.toString().getBytes());
}
}
- Person实体类
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@Accessors(chain = true)
public class Person implements Serializable {
private Integer id;
private String name;
private Integer age;
private Boolean sex;
private Telephone telephone;
}
- Telephone实体类
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@Accessors(chain = true)
public class Telephone implements Serializable {
private Integer id;
private String number;
}
- PersonMapper接口
import com.mo.rediscache.model.entity.Person;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface PersonMapper {
// 获取所有数据
List<Person> findAll();
}
- TelephoneMapper接口
import com.mo.rediscache.model.entity.Telephone;
import org.springframework.stereotype.Repository;
@Repository
public interface TelephoneMapper {
// 通过ID查询数据
Telephone getTelephoneById(Integer id);
}
- PersonMapper.xml映射文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mo.rediscache.mapper.PersonMapper">
<!--开启二级缓存-->
<cache type="com.mo.rediscache.cache.RedisCache" />
<resultMap id="personMap" type="Person">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<result property="sex" column="sex"/>
<association property="telephone" select="com.mo.rediscache.mapper.TelephoneMapper.getTelephoneById" column="telephone_id"></association>
</resultMap>
<select id="findAll" resultMap="personMap">
SELECT id, name, age, sex, telephone_id
FROM person
</select>
</mapper>
- TelephoneMappe.xml映射文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mo.rediscache.mapper.TelephoneMapper">
<!--开启二级缓存关联-->
<cache-ref namespace="com.mo.rediscache.mapper.PersonMapper"/>
<select id="getTelephoneById" parameterType="Integer" resultType="Telephone">
SELECT id, number
FROM telephone
WHERE id = #{id}
</select>
</mapper>
- PersonService接口
import com.mo.rediscache.model.entity.Person;
import java.util.List;
public interface PersonService {
List<Person> findAll();
}
- TelephoneService接口
import com.mo.rediscache.model.entity.Telephone;
public interface TelephoneService {
// 通过ID查询数据
Telephone getTelephoneById(Integer id);
}
- PersonServiceImpl实现类
import com.mo.rediscache.mapper.PersonMapper;
import com.mo.rediscache.model.entity.Person;
import com.mo.rediscache.service.PersonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class PersonServiceImpl implements PersonService {
@Autowired
private PersonMapper personMapper;
@Override
public List<Person> findAll() {
return personMapper.findAll();
}
}
- TelephoneServiceImpl实现类
import com.mo.rediscache.mapper.TelephoneMapper;
import com.mo.rediscache.model.entity.Telephone;
import com.mo.rediscache.service.TelephoneService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class TelephoneServiceImpl implements TelephoneService {
@Autowired
private TelephoneMapper telephoneMapper;
@Override
public Telephone getTelephoneById(Integer id) {
return telephoneMapper.getTelephoneById(id);
}
}
- application启动类
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan("com.mo.rediscache.mapper")
@SpringBootApplication
public class RediscacheApplication {
public static void main(String[] args) {
SpringApplication.run(RediscacheApplication.class, args);
}
}
- 测试类
import com.mo.rediscache.model.entity.Person;
import com.mo.rediscache.service.PersonService;
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.test.context.junit4.SpringRunner;
import java.util.List;
@SpringBootTest(classes = RediscacheApplication.class)
@RunWith(SpringRunner.class)
public class RediscacheApplicationTests {
@Autowired
private PersonService personService;
@Test
public void test() {
System.out.println("第一次获取值:");
List<Person> personList = personService.findAll();
personList.forEach(System.out::println);
System.out.println("================================");
System.out.println("第二次获取值:");
List<Person> personList2 = personService.findAll();
personList2.forEach(System.out::println);
}
}
2.3.3 通过接管spring提供的session实现分布式session管理
- pom.xml依赖
<dependencies>
<!--web依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--redis操作依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--redis管理session依赖-->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<!--测试依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
- application.yml配置
# web端口
server:
port: 8080
spring:
application:
name: redissession
# redis连接配置
redis:
host: 192.168.150.128
port: 6379
database: 0
- Redis管理Session配置类
import org.springframework.context.annotation.Configuration;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
/**
* Redis管理Session配置类
*/
@Configuration
@EnableRedisHttpSession // 开启RedisHttpSession
public class RedisSessionManagerConfiguration {
}
- controller测试
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@Controller
@RequestMapping("/test")
public class TestController {
@RequestMapping("/look")
public void look(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 获取Session
HttpSession session = request.getSession();
// 获取Session中的数据
Integer look = (Integer) session.getAttribute("look");
if (look == null) {
look = 0;
}
look += 1;
// 同步Redis中的Session数据
session.setAttribute("look", look);
response.getWriter().println("look: " + look);
response.getWriter().println("sessionid: " + session.getId());
}
}