Redis用法详细总结
文章目录1 Redis简介1.1 关系型数据库的特点1.2 Redis的特点1.3 Redis开发中的应用2 Redis的安装1. 上传 redis-3.x.x.tar.gz 到linux虚拟机的 /opt 文件夹2. 安装gcc3. 解压缩 redis-3.x.x.tar.gz4. 进入到redis根目录,进行编译、安装5. 将 redis-3.x.x/redis.conf 复制到 /etc/r
文章目录
1 Redis简介
Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value的NoSQL(Not Only SQL)数据库。
SQL (Struct Query Lanauge 结构化的查询语言) 引申含义 RDB产品,传统的关系型数据库,存储格式化的表格数据。
Not Only SQL 不仅仅只有关系型数据库 引申含义:非关系型数据库。存储半格式化和非格式化的数据,如k-v、json、xml
1.1 关系型数据库的特点
关系型数据库特点:
- 存储结构化数据
- 强事务
- 在磁盘中存储数据
- 数据量到达一定量级,查询性能就会出现瓶颈
- 支持SQL
1.2 Redis的特点
Redis的特点:
- 存储非结构化的数据:k-v方式存储数据
- 弱事务,但一般能保证最终一致
- 在内存中存储数据,但能自动持久化
- 查询性能非常好
- 不支持SQL,需要使用特定的命令
- 支持集群、数据分片,扩展容易
Redis就是一个在内存中,存储k-v格式数据,支持自动持久化的NoSQL型数据库。
1.3 Redis开发中的应用
典型应用:
- 需要持久化,但对事务要求不高的数据:购物车
- 充当应用中的缓存
- 对tomcat集群的session进行管理
2 Redis的安装
1. 上传 redis-3.x.x.tar.gz 到linux虚拟机的 /opt 文件夹
2. 安装gcc
[root@localhost ~]# yum install -y gcc
3. 解压缩 redis-3.x.x.tar.gz
[root@localhost opt]# tar xzvf redis-3.2.9.tar.gz
4. 进入到redis根目录,进行编译、安装
[root@localhost opt]# cd redis-3.2.9
[root@localhost redis-3.2.9]# make
[root@localhost redis-3.2.9]# make install
5. 将 redis-3.x.x/redis.conf 复制到 /etc/redis/目录下
[root@localhost redis-3.2.9]# mkdir -p /etc/redis/
[root@localhost redis-3.2.9]# cp redis.conf /etc/redis/
6. 启动redis
[root@localhost redis-3.2.9]# redis-server /etc/redis/redis.conf
6255:M 08 Jun 00:19:28.368 * Increased maximum number of open files to 10032 (it was originally set to 1024).
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 3.2.9 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
| `-._ `._ / _.-' | PID: 6255
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
3 Redis客户端的使用
在xshell中复制一个连接虚拟机的窗口。
1. 打开客户端
[root@localhost ~]# redis-cli
127.0.0.1:6379>
2. 关闭redis数据库
127.0.0.1:6379> shutdown
not connected>
3. 关闭客户端
not connected> exit
[root@localhost ~]#
4. 让数字自增和自减
set age 20 //添加一个键age值为20
incr age //让age值自增 age就变成了21
decr age //让age值自减 age又变成了20
5. redis存储数据的有效时长
set age 20
expire age 60 //让age的有效时长为60秒,超过60秒该数据就失效了。
ttl age //查看该键age还有多长有效时长,单位是秒。-1永久有效。-2失效。
persist age //让age重新永久有效
String类型数据的操作
Redis是k-v数据格式的数据库,v有多种类型,下面演示v为字符串的操作。
1. 增
127.0.0.1:6379> set name zhangsan
OK
127.0.0.1:6379> get age
"18"
2. 查
查看所有的key
127.0.0.1:6379> keys *
1) "age"
2) "name"
127.0.0.1:6379> get name
"zhangsan"
127.0.0.1:6379> get age
"18"
3. 改
127.0.0.1:6379> set name lisi
OK
127.0.0.1:6379> set age 16
OK
127.0.0.1:6379> get name
"lisi"
127.0.0.1:6379> get age
"16"
4. 删
127.0.0.1:6379> del name
(integer) 1
127.0.0.1:6379> del age
(integer) 1
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> get age
(nil)
127.0.0.1:6379> flushdb
OK 清除所有数据
注意:
- 字符串外的单引号或双引号可以省略
- 命令结束直接回车,不要添加分号
4 Java操作Redis
和在Java中操作关系型数据库类似,也可以在Java中操作Redis数据库。Jedis是Redis官方推荐的Java连接开发工具,通过Jedis操作Redis数据库。
准备工作:关闭linux虚拟机防火墙
systemctl stop firewalld
编辑 /etc/redis/redis.conf
bind 127.0.0.1 改为如下所示:
bind 127.0.0.1 redis服务器的ip
比如:
bind 127.0.0.1 192.168.84.141
重启redis服务让配置文件生效。
对jedis进行测试
-
导入依赖
redis.clients
jedis
2.9.0
-
编码
@Test
public void testSet(){
//创建连接
// ip为redis所在机器的地址
// 端口号为redis的启动时显示的服务端口
Jedis jedis = new Jedis(“192.168.84.141”,6379);
//执行操作
jedis.set(“name”, “zhangsan”);
jedis.set(“age”, “18”);
//释放资源
jedis.close();
}@Test public void testGet(){ //创建连接 Jedis jedis = new Jedis("192.168.84.141", 6379); //执行操作 String name = jedis.get("name"); System.out.println("name = " + name); String age = jedis.get("age"); System.out.println("age = " + age); //释放资源 jedis.close(); } @Test public void testDel(){ //创建连接 Jedis jedis = new Jedis("192.168.84.141", 6379); //执行操作 jedis.del("name"); jedis.del("age"); //释放资源 jedis.close(); }
5 JedisUtils工具类
为提升Jedis操作Redis的性能,可以使用JedisPool连接池来管理jedis对象。
JedisPool的使用:
@Test
public void testPool(){
//创建连接池的配置对象
JedisPoolConfig config = new JedisPoolConfig();
//从连接池获取连接时,是否检测连接的有效性
config.setTestOnBorrow(true);
//可用连接实例的最大数目,默认值为8
config.setMaxTotal(100);
//最大空闲连接数, 默认8个
config.setMaxIdle(10);
//最小空闲连接数,默认8个
config.setMinIdle(8);
//没有空闲连接时,最大的等待毫秒数
config.setMaxWaitMillis(60000);
//创建连接池
JedisPool pool = new JedisPool(config, "192.168.44.128", 6379);
//获取连接
Jedis jedis = pool.getResource();
//执行操作
jedis.set("name", "zhangsan");
String name = jedis.get("name");
System.out.println("name = " + name);
//释放资源
jedis.close();
}
redis.properties:抽取配置参数
# 最大空闲数量
redis.maxIdle=50
# 最小空闲数量
redis.minIdle=10
# 最大数量
redis.maxTotal=500
# 建立连接最大等待时间,单位毫秒
redis.maxWaitMillis=30000
# 从连接池中获取连接时,是否检查连接的可用性
redis.testOnBorrow=true
# redis机器ip
redis.hostName=192.168.146.20
# redis端口号
redis.port=6379
工具类:
JedisUtils.java:抽取共性操作
public class JedisUtils {
private static JedisPool pool;
static{
//读取redis.properties文件
InputStream in = JedisUtils.class.getResourceAsStream("/redis.properties");
Properties env = new Properties();
try {
env.load(in);
in.close();
}catch(IOException e){
e.printStackTrace();
throw new RuntimeException(e);
}
JedisPoolConfig config = new JedisPoolConfig();
String maxIdle = env.getProperty("redis.maxIdle");
if (maxIdle != null) {
config.setMaxIdle(Integer.parseInt(maxIdle));
}
String minIdle = env.getProperty("redis.minIdle");
if(minIdle != null){
config.setMinIdle(Integer.parseInt(minIdle));
}
String maxTotal = env.getProperty("redis.maxTotal");
if(maxTotal != null){
config.setMaxTotal(Integer.parseInt(maxTotal));
}
String maxWaitMillis = env.getProperty("redis.maxWaitMillis");
if (maxWaitMillis != null) {
config.setMaxWaitMillis(Long.parseLong(maxWaitMillis));
}
String testOnBorrow = env.getProperty("redis.testOnBorrow");
if(testOnBorrow != null){
config.setTestOnBorrow(Boolean.parseBoolean(testOnBorrow));
}
String hostName = env.getProperty("redis.hostName");
String port = env.getProperty("redis.port");
pool = new JedisPool(config, hostName, Integer.parseInt(port == null ? "6379" : port));
}
public static Jedis getJedis(){
return pool.getResource();
}
public static void close(Jedis jedis){
if(jedis != null){
jedis.close();
}
}
}
5.1 使用jedis工具类实现手机验证码功能(生成6位随机验证码案例)
//生成六位的手机随机验证码
public static String randomCode(){
Random random=new Random();
StringBuilder sb=new StringBuilder();
for(int i=0;i<6;i++) {
int randomNum = random.nextInt(10);
sb.append(randomNum);
}
return sb.toString();
}
/**
* 把验证码放入到redis里面,存储60秒,验证是否超过3次。
* @param phone 手机号码
*/
public static void saveCode(String phone){
String code = randomCode();//随机手机验证码
//redis里面存两个键,一个键verifyCode150098776766:code 值是验证码
//另一个键 verifyCode150098776766:count 今日该手机发送验证码的次数
String codeKey="verifyCode"+phone+":code";
String countKey="verifyCode"+phone+":count";
//获取到数据库连接
Jedis jedis=JedisUtil.getJedis();
String countValue = jedis.get(countKey);
//第一次发送验证码
if(countValue==null){
jedis.setex(codeKey,60,code);//设值的同时添加有效时长
jedis.set(countKey,"1");//表示第一次发出验证码
}else if(Integer.parseInt(countValue)<3){
jedis.setex(codeKey,60,code);//设值的同时添加有效时长
jedis.incr(countKey);
}else{
System.out.println("今日验证码次数达到上限3次。不可以在发出验证码了");
}
jedis.close();
}
/**
* 比对验证码
* @param phone 用户手机号
* @param userCode 用户输入的验证码
*/
public static void compareCode(String phone,String userCode){
String codeKey="verifyCode"+phone+":code";
Jedis jedis=JedisUtil.getJedis();
String realCode = jedis.get(codeKey);
if(userCode.equals(realCode)){
System.out.println("验证通过!!");
}else{
System.out.println("验证失败!!!");
}
jedis.close();
}
6 序列化和反序列化
对象序列化:将对象的状态信息持久保存的过程。
对象反序列化:根据对象的状态信息恢复对象的过程。
在Redis中有2种常用的方式:字节数组和json串
6.1字节数组
添加依赖:
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version>
</dependency>
@Test
public void testJDKSerializer(){
User user = new User(1, "zhangsan",18,10000.0,new Date());
//使用commons-lang3中的工具将对象转换为字节数组
byte[] bs = SerializationUtils.serialize(user);
Jedis jedis = JedisUtils.getJedis();
jedis.set("u".getBytes(), bs);
byte[] bs2 = jedis.get("u".getBytes());
//使用commons-lang3中的工具将为字节数组转换为对象
User user2 = SerializationUtils.deserialize(bs2);
System.out.println("user2 = " + user2);
JedisUtils.close(jedis);
}
注意:序列化的类型,必须实现Serializable接口
6.2 json串
添加依赖:
<!-- 引入jackson依赖-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.3</version>
</dependency>
@Test
public void testJsonSerializer() throws JsonProcessingException {
User user = new User(1, "zhangsan",18,10000.0,new Date());
//使用JSON工具将对象转换为json字符串
ObjectMapper mapper = new ObjectMapper();
String userJson = mapper.writeValueAsString(user);
Jedis jedis = JedisUtils.getJedis();
jedis.set("u", userJson);
String userJson2 = jedis.get("u");
//使用JSON工具将json字符串转换为对象
User user2 = mapper.readValue(userJson2, User.class);
System.out.println("user2 = " + user2);
JedisUtils.close(jedis);
}
因为json格式支持多种编程语法,便于数据在不同的编程语言中传递,实战中json格式更为常见。
7 Redis管理Tomcat集群下的Session
Tomcat集群下session数据丢失的问题:
session是由tomcat创建管理的,集群中tomcat服务器相互独立,session不能共享。
nginx分发同1个用户的多次请求到达不同tomcat服务器时,就会发生session数据的问题。
解决方案:
1. ip黏着
将nginx的负载均衡策略设置为ip_hash.
缺点:1 负载可能不均衡
2 如果tomcat宕机,session的数还是会丢失
2. 借助于Redis数据库完成集群间的session共享
tomcat新建session后,将session以sessionId=session对象的形式写入到redis中。
用户再次发起请求会携带sessionId, 在任何一个tomcat服务器中都可以通过sessionId从redis中得到session。
2 使用Redis完成tomcat集群的session共享
-
tomcat中添加依赖
tomcat/lib下添加:
commons-logging-1.2.jar
commons-pool2-2.4.2.jar
jedis-2.9.0.jar
tomcat-cluster-redis-session-manager-3.0.1.jar -
在tomcat/conf下添加redis-data-cache.properties,并配置redis信息
#redis.hosts=reids服务ip以及端口号redis.hosts=192.168.232.107:6379#- redis password#redis.password=lolaage_cache 有密码写密码,没有注释就可以 -
配置tomcat/conf的context.xml
-
重启tomcat,重新测试
8 Redis中的数据结构
传统键值存储是关联字符串值到字符串键,但是 Redis 的值不仅仅局限于简单字符串,还可以持有更复杂的数据结构。下面列的是 Redis 支持的所有数据结构,后面将逐一介绍:
- String(字符串)
- List(列表)
- Set(集合)
- Hash(哈希,键值对集合)
- SortedSet(zset,排序集合)
8.1 String(字符串)
应用场景:粉丝数,投票数
Redis中的String,除了字符串外,还可以存:储数字以及二进制数据。
增:
127.0.0.1:6379> set name zhangsan
OK
127.0.0.1:6379> set age 18
OK
批量添加
127.0.0.1:6379> mset score 100.0 sex M
OK
删:
127.0.0.1:6379> del name
(integer) 1
127.0.0.1:6379> get name
(nil)
改:
数字自增
127.0.0.1:6379> incr age
(integer) 19
指定自增的数值
127.0.0.1:6379> incrby age 2
(integer) 21
数字自减
127.0.0.1:6379> decr age
(integer) 20
指定自减的数值
127.0.0.1:6379> decrby age 2
(integer) 18
查:
127.0.0.1:6379> get age
"18"
批量获取
127.0.0.1:6379> mget score sex
1) "100.0"
2) "M"
127.0.0.1:6379> set name zhangsan
OK
获取值的长度
127.0.0.1:6379> strlen name
(integer) 5
8.2 List(列表)
应用场景:排队。队列
增:
向mylist列表尾部添加多个数据
127.0.0.1:6379> rpush mylist xiao1hei xiao2hei xiao3hei
(integer) 3
向mylist列表头部添加多个数据
127.0.0.1:6379> lpush mylist xiao0hei xiao-1hei
(integer) 5
查:
127.0.0.1:6379> llen mylist
(integer) 5
127.0.0.1:6379> lrange mylist 0 4
1) "xiao-1hei"
2) "xiao0hei"
3) "xiao1hei"
4) "xiao2hei"
5) "xiao3hei"
查看全部,固定写法
lrange mylist 0 -1
127.0.0.1:6379> lindex mylist 2
"xiao-1hei"
删:
127.0.0.1:6379> lpop mylist
"xiao-1hei"
127.0.0.1:6379> rpop mylist
"xiao3hei"
//lrem list count value
//从list中删除count个value,
//count=0删除全部 count>0从左开始删除 count<0从右开始删除
127.0.0.1:6379> rpush mylist xiao0hei xiao0hei xiao0hei
(integer) 6
127.0.0.1:6379> lrem mylist 3 xiao0hei
(integer) 3
改:
127.0.0.1:6379> lset mylist 0 xiaoheihei
OK
127.0.0.1:6379> lindex mylist 0
"xiaoheihei"
8.3 Set(集合)
应用场景:共同好友
增:
127.0.0.1:6379> sadd myset a b
(integer) 2
127.0.0.1:6379> sadd myset b c d
(integer) 2
查:
127.0.0.1:6379> smembers myset
1) "d"
2) "c"
3) "b"
4) "a"
删:
删除元素
127.0.0.1:6379> srem myset a
(integer) 1
127.0.0.1:6379> sismember myset a
(integer) 0
集合间的运算:
127.0.0.1:6379> sadd myset1 a b c
(integer) 3
127.0.0.1:6379> sadd myset2 b d e
(integer) 3
127.0.0.1:6379> sadd myset3 c d f
(integer) 3
myset1: a b c
myset2: b d e
myset3: c d f
获取多个集合间的差集
127.0.0.1:6379> sdiff myset1 myset2
1) "c"
2) "a"
127.0.0.1:6379> sdiff myset2 myset1
1) "d"
2) "e"
127.0.0.1:6379> sdiff myset1 myset2 myset3
1) "a"
获取多个集合间的交集
127.0.0.1:6379> sinter myset1 myset2
1) "b"
127.0.0.1:6379> sinter myset2 myset3
1) "d"
127.0.0.1:6379> sinter myset1 myset2 myset3
(empty list or set)
获取多个集合间的并集
127.0.0.1:6379> sunion myset1 myset2 myset3
1) "d"
2) "b"
3) "e"
4) "f"
5) "c"
6) "a"
8.4 Hash(键值对集合)
应用场景:存储有关联的数据,对象的另一种存放。
增:
127.0.0.1:6379> hset myhash name zhangsan
(integer) 1
127.0.0.1:6379> hmset myhash age 18 sex m
OK
不存在某个key时才添加
127.0.0.1:6379> hsetnx myhash name lisi
(integer) 0
127.0.0.1:6379> hsetnx myhash phone 18530031576
(integer) 1
查:
127.0.0.1:6379> hget myhash name
"zhangsan"
127.0.0.1:6379> hmget myhash name age sex
1) "zhangsan"
2) "18"
3) "m"
删:
127.0.0.1:6379> hdel myhash phone
(integer) 1
127.0.0.1:6379> hget myhash phone
(nil)
8.5 SortedSet(ZSet 排序集合)
应用场景:排行榜
增:
127.0.0.1:6379> zadd mysortset 18 zhaoxs 20 fanmw 22 liuyh 30 wangmj
(integer) 4
查:
获取特定元素的分数
127.0.0.1:6379> zscore mysortset zhaoxs
"18"
获取排序后指定下标范围的元素
127.0.0.1:6379> zrange mysortset 0 2
1) "zhaoxs"
2) "fanmw"
3) "lisih"
获取所有元素
127.0.0.1:6379> zrange mysortset 0 -1
1) "zhaoxs"
2) "fanmw"
3) "lisih"
4) "wangmj"
按照分数大小范围获取元素
127.0.0.1:6379> zrangebyscore mysortset 20 22
1) "fanmw"
2) "lisih"
按照分数大小范围获取元素,并进行过滤
127.0.0.1:6379> zrangebyscore mysortset 16 30
1) "zhaoxs"
2) "fanmw"
3) "lisih"
4) "wangmj"
127.0.0.1:6379> zrangebyscore mysortset 16 30 limit 2 2
1) "lisih"
2) "wangmj"
删:
127.0.0.1:6379> zrem mysortset wangmj
(integer) 1
127.0.0.1:6379> zscore mysortset wangmj
(nil)
改:
修改分数
127.0.0.1:6379> zincrby mysortset 2 zhaoxs
"20"
127.0.0.1:6379> zscore mysortset zhaoxs
"20"
注意:redis根据数据类型不同将命令分成不同的组,可以通过help命令获取帮助。
help @string
help @list
help @set
help @hash
help @sorted_set
flushdb:清除数据库里面所有的数据
9 Redis中设置key的过期时间
Redis中可以设置数据的过期时间,一旦过期自动删除数据。
1. 设置过期时间
127.0.0.1:6379> set name ok
//设置10s后过期,expire单位秒
127.0.0.1:6379> expire name 10
//设置10s后过期,pexpire 单位毫秒
127.0.0.1:6379> pexpire age 10000
(integer) 1
2. 查看剩余时间
查看剩余存活时长,单位秒
127.0.0.1:6379> ttl name
(integer) 7
查看剩余存活时长,单位毫秒
127.0.0.1:6379> pttl name
(integer) 4006
3. 取消过期
127.0.0.1:6379> set age 18
OK
127.0.0.1:6379> expire age 20
(integer) 1
127.0.0.1:6379> ttl age
(integer) 15
取消过期
127.0.0.1:6379> persist age
(integer) 1
ttl返回-1表示没有设置过期时间,返回-2表示数据不存在
127.0.0.1:6379> ttl age
(integer) -1
127.0.0.1:6379> get age
"18"
应用:手机验证码、黑名单、缓存
10 Springboot操作Redis
Spring的spring-data-redis模块中封装了RedisTemplate对象来进行对Redis的各种操作,它支持所有的Redis原生的api。提供了连接池自动管理、高度统一的Api、灵活的定制化,简化Java操作Redis的编码工作。
10.1 第1个RedisTemplate示例
-
导入依赖
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-data-redis
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.9.0</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!--springboot做单元测试的依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency>
-
配置
application.yml
spring:
redis:
host: 192.168.232.107
port: 6379
jedis:
pool:
max-active: 500
max-idle: 50
min-idle: 10
max-wait: 30000 -
入口类:配置RedisTemplate
@Configuration
public class RedisConfig{
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);StringRedisSerializer stringRedisSerializer= new StringRedisSerializer(); GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); redisTemplate.setKeySerializer(stringRedisSerializer); redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer); redisTemplate.setHashKeySerializer(stringRedisSerializer); redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer); return redisTemplate; } }
-
编码
@RuntWith(SpringRunner.class)
@SpringBootTest(classes=RedisDay02Application.class)
public class RedisTemplateTest{
@Autowired
//获取RedisTemplate工具
private RedisTemplate<String,Object> redisTemplate;
@Test
public void testValueSet(){//获取操作特定数据类型的operations对象 ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue(); //通过operations对象操作数据 valueOperations.set("name","zhangsan"); valueOperations.set("age",18, Duration.ofSeconds(60)); } @Test public void testValueGet(){ ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue(); Object name = valueOperations.get("name"); Object age = valueOperations.get("age"); System.out.println("name = " + name); System.out.println("age = " + age); } }
10.2 RedisTemplate的常用api
spring-data-redis针对jedis客户端中大量api进行了归类封装,将同一类型操作封装为operations接口。根据Redis的不同数据类型,定义了如下的operations接口:
- ValueOperations:提供了对String类型的操作
- ListOperations :提供了对List类型的数据操作
- SetOperations:提供了对Set类型的数据操作
- HashOperations:提供了对Map类型的数据操作
- ZSetOprations:提供了对ZSet类型的数据操作
3.2.1 ValueOperations
-
添加:set
ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
valueOperations.set(“name”,“zhangsan”);//添加
valueOperations.set(“age”,18, Duration.ofSeconds(60));//添加有时效的数据
Map<String, Object> map = new HashMap<>();
map.put(“score”,100.0);
map.put(“sex”,“男”);
valueOperations.multiSet(map);//批量添加 -
删除:delete
redisTemplate.delete(“name”); -
修改:set、increment、decremnt
ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
valueOperations.set(“age”,18);
valueOperations.increment(“age”);//自增
valueOperations.increment(“age”,10);//加10
valueOperations.decrement(“age”);//自减
valueOperations.decrement(“age”,10);//减10 -
查询:get、mget
ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
Object name = valueOperations.get(“name”);
Object age = valueOperations.get(“age”);
System.out.println("name = " + name);
System.out.println("age = " + age);//批量查询 Collection<String> keys = new ArrayList<String>(0); keys.add("score"); keys.add("sex"); List<Object> values = valueOperations.multiGet(keys);
3.2.2 ListOperations
-
添加:push
ListOperations<String, Object> listOperations = redisTemplate.opsForList();
listOperations.leftPush(“list”,“1”);
listOperations.leftPushAll(“list”,“2,”,“3”);listOperations.rightPush("list","2"); listOperations.rightPushAll("list","3","4");
-
删除:pop
ListOperations<String, Object> listOperations = redisTemplate.opsForList();
Object leftPop = listOperations.leftPop(“list”);
Object rightPop = listOperations.rightPop(“list”);
System.out.println("leftPop = " + leftPop);
System.out.println("rightPop = " + rightPop); -
修改:set
ListOperations<String, Object> listOperations = redisTemplate.opsForList();
listOperations.set(“list”,1,“new value”); -
查询:index、size、range
ListOperations<String, Object> listOperations = redisTemplate.opsForList();
Object value = listOperations.index(“list”, 0);
Long size = listOperations.size(“list”);
List list = listOperations.range(“list”, 0, -1);
3.2.3 SetOperations
-
添加:add
SetOperations<String, Object> setOperations = redisTemplate.opsForSet();
setOperations.add(“set”, “xiao1hei”, “xiao2hei”); -
删除:remove
SetOperations<String, Object> setOperations = redisTemplate.opsForSet();
setOperations.remove(“set”, “xiao1hei”); -
集合运算:difference、union、intersect
SetOperations<String,Object> setOperations = redisTemplate.opsForSet();
setOperations.add(“set1”,1,2,3,4);
setOperations.add(“set2”,2,3,4,5);
setOperations.add(“set3”,3,4,5,6);Set<Object> difference = setOperations.difference("set1", "set2");//set1-set2 Collection<String> keys = new ArrayList<String>(); keys.add("set1"); keys.add("set2"); keys.add("set3"); Set<Object> union = setOperations.union(keys);//set1 + set2 + set3 Set<Object> intersect = setOperations.intersect(keys);//求交集
3.2.4 HashOperations
-
添加:put、putAll
HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
hashOperations.put(“map”,“k1”,“v1”);
Map<String, String> values = new HashMap<>();
values.put(“k2”, “v2”);
values.put(“k3”, “v3”);
hashOperations.putAll(“map”,values); -
删除:
HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
hashOperations.delete(“map”,“k1”,“k2”); -
修改:
HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
hashOperations.put(“map”,“age”,18);
hashOperations.increment(“map”,“age”,10); -
查询:
HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
Object v1 = hashOperations.get(“map”, “k1”);
Collection keys = new ArrayList<>();
keys.add(“k2”);
keys.add(“k3”);
List values = hashOperations.multiGet(“map”, keys);
Boolean hasKey = hashOperations.hasKey(“map”, “k1”);
Long size = hashOperations.size(“map”);
3.2.5 ZSetOperations
-
添加:
ZSetOperations<String, Object> zSetOperations = redisTemplate.opsForZSet();
zSetOperations.add(“zset”,“zhangsan”,100);
zSetOperations.add(“zset”,“lisi”,60); -
删除:
zSetOperations.remove(“zset”,“zhangsan”,“lisi”);
zSetOperations.removeRange(“zset”,0,2);
zSetOperations.removeRangeByScore(“zset”,50,99.0); -
修改:
zSetOperations.incrementScore(“zset”, “lisi”, 10.0); -
查询:
Set zset1 = zSetOperations.range(“zset”, 0, -1);
Set zset2 = zSetOperations.rangeByScore(“zset”, 40, 100);Set<ZSetOperations.TypedTuple<Object>> scores = zSetOperations.rangeWithScores("zset", 0, -1); for (ZSetOperations.TypedTuple e:scores) { System.out.println(e.getValue()+" "+e.getScore()); } Set<ZSetOperations.TypedTuple<Object>> scores2 = zSetOperations.rangeByScoreWithScores("zset", 40, 100); for (ZSetOperations.TypedTuple e:scores2) { System.out.println(e.getValue()+" "+e.getScore()); }
11 Redis缓存
11.1 Redis缓存引言
缓存:对于数据库中的热点数据的备份,便于访问,提高应用性能。
单机架构的缓存方案
EhCache直接将数据缓存在JVM中,速度快,效率高。但是在分布式集群环境下,缓存管理非常麻烦,比如:当修改了一条数据后,必须通知到缓存了该数据的所有缓存。
解决方案:Redis缓存
Redis基于内存操作,性能远超关系型数据库,可以代替EhCache充当缓存。单独部署Redis服务,应用通过网络和Redis通信,虽效率略低于EhCache,但处理集群分布式缓存有成熟的方案。
11.2 Redis缓存的使用
Redis缓存的设计思路:
- 在执行查询时,先查询redis缓存,如果有数据则不在调用dao直接返回;如果查不到,才调用dao,并将数据保存到缓存
- 在执行增删改后,需要清空缓存,避免脏数据
为避免操作缓存的代码和原始业务代码耦合,不能将操作缓存的代码硬编码到业务方法中。可以将操作Redis缓存的代码定义成Advice(增强),使用AOP的方式动态增强。
4.2.1实战中Spring Boot的Redis缓存配置
事实上,在Springboot中配置缓存无需手写增强类,Springboot对缓存的AOP方式进行了抽取封装,内置了一套开箱即用的缓存机制。
注解:Spring内置了缓存注解
- Cacheable:用在方法上,执行方法前先查询缓存,如果缓存有数据,直接返回;如果缓存中没有数据,则执行查询方法,并将结果保存到缓存中
- CacheEvict:用在方法上,可以在方法执行前或后删除缓存
增强类: Spring内置了RedisCacheManager缓存增强类
具体步骤:
-
引入依赖。
org.springframework.boot
spring-boot-starter-data-redis
2.1.4.RELEASE
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.9.0</version> </dependency>
-
在目标方法上面使用缓存。
@CacheEvict(value=“NewsServiceImpl”,allEntries = true,beforeInvocation = true)
@Cacheable(value=“NewsServiceImpl”,key="#root.methodName+#id") -
在Application启动类上面添加开启缓存注解。
@EnableCaching//开启缓存
public class Application {} -
在配置类中对redis连接进行管理。
//配置缓存管理器
@Bean
public CacheManager cacheManager(RedisConnectionFactory connectionFactory){RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory); return new RedisCacheManager(redisCacheWriter,getRedisCacheConfiguration(20), getRedisCacheConfigurationMap()); } private Map<String, RedisCacheConfiguration> getRedisCacheConfigurationMap(){ Map<String, RedisCacheConfiguration> redisCacheConfigurationMap = new HashMap<>(); //以NewsServiceImpl开头的缓存要存储100秒 redisCacheConfigurationMap.put("NewsServiceImpl", getRedisCacheConfiguration(100)); return redisCacheConfigurationMap; } //RedisCacheConfiguration 用于负责Redis的缓存配置 private RedisCacheConfiguration getRedisCacheConfiguration(int seconds){ RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig(); GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); return redisCacheConfiguration .serializeValuesWith( RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer) ) .entryTtl(Duration.ofSeconds(seconds)); }
-
在application.yml中对redis服务器进行配置。
spring:
redis:
lettuce:
pool:
max-active: 500
max-idle: 50
min-idle: 10
max-wait: 30000
host: 192.168.232.107
port: 6379
更多推荐
所有评论(0)