复习
- redis
- 概念: 开源的内存数据结构存储,可以用作数据库、缓存、消息中间件等。
- 数据结构:string\hash\set\list\sorted set\bitmap\hyperloglogs\geospatial
- 特性:持久化、通过哨兵实现高可用、通过cluster实现自动分区、事务、lua脚本支持、LRU内存清理策略
- 安装 yum install -y redis
- key相关的命令
- set
- get
- expire pexpire <=> persist
- ttl pttl
- del
- keys
- exists
- type
- rename
- 概念: 开源的内存数据结构存储,可以用作数据库、缓存、消息中间件等。
String
set 新增或者修改
- EX 过期时间秒
- PX 过期时间毫秒
- NX 新增操作,必须不存在,如果存在则失败
- XX 修改操作,必须存在,如果不存在则失败
get 获取
mget 一次获取多个key的值
getset
strlen 长度
incr 对数字加一
decr 对数字减一
incrby 对数字加N
decrby 对数字减N
append 追加
mset user:huangguang:degree baobiao user:huangguange:age 18 user:huangguange:gender M
mget user:cyx:degree user:cyx:age user:cyx:gender
使用场景:
- 统计:在线人数
- 缓存
- 分布式锁:排他性,A加锁之后其他人加不了锁
- set NX 加锁 加过期时间防止死锁 、 value表示加锁者 ```bash 127.0.0.1:6379> set lock:balance:decr james ex 30 OK 127.0.0.1:6379> set lock:balance:decr durant ex 30 NX (nil)
execA set lock lucas ex 30 NX | set lock curry ex 30 NX(失败)<br />execB<br />execC 解锁 | set lock curry ex 30 NX(成功)
- del 解锁 不能直接删除,判断value是否为当前用户,当前用户是否为加锁者 if(val==当前用户){del lock}
- 从获取值到判断时存在一段时间间隔,可能存在并发问题,需要保证判断和删除两个操作的原子性,使用lua脚本封装
<a name="LNLSa"></a>
# Hash K-V结构
<br />hset 添加修改<br />hget 获取<br />hmset 添加修改多个字段<br />hmget 获取多个字段<br />hgetall 获取所有字段<br />hincrby 增加某个数字的值,可以为负数<br />hexists 判断是否有字段
```bash
127.0.0.1:6379> hset user:cyx age 23
(integer) 1
127.0.0.1:6379> hset user:cyx score 1000
(integer) 1
127.0.0.1:6379> hget user:cyx age
"23"
127.0.0.1:6379> hgetall user:cyx
1) "age"
2) "23"
3) "score"
4) "1000"
127.0.0.1:6379> hget user:cyx score
"1000"
127.0.0.1:6379> hgetall user:cyx
1) "age"
2) "23"
3) "score"
4) "1000"
127.0.0.1:6379> hmset user:hg age 18 score 1000 hobby coding
OK
127.0.0.1:6379> hmget user:hg age score hobby
1) "18"
2) "1000"
3) "coding"
127.0.0.1:6379> hincrby user:hg age 10
(integer) 28
127.0.0.1:6379> hincrby user:hg age -5
(integer) 23
127.0.0.1:6379> hexists user:hg age
(integer) 1
127.0.0.1:6379> hexists user:hg honor
(integer) 0
127.0.0.1:6379> hexists user:hg lunch
(integer) 0
127.0.0.1:6379> hkeys user:hg
1) "age"
2) "score"
3) "hobby"
127.0.0.1:6379> hvals user:hg
1) "23"
2) "1000"
3) "coding"
127.0.0.1:6379> hlen user:hg
(integer) 3
使用场景:
- 缓存,存对象
- 短网址生成器 短网址<=>真实网址
- 用户登录存储
- 手机验证码,带过期时间
- …
List
LPUSH 加入,从尾部加入
RPUSH
LINSERT 插入
lset
LPOP 弹出,从头部取出
RPOP
LREM key count element
删除等于element的元素
删除count次
count如果>0 从左往右 头到尾
count<0 从右往左 尾到头
count=0 删除所有
LLEN
lrange ```bash lpush eat pty hqh ls fg
lrange eat 0 -1 rpush eat cyx
linsert eat AFTER hqh zyq linsert eat BEFORE hqh pyy lpop eat lindex eat 1
lrem eat 3 pty
<a name="ceJa8"></a>
## 使用场景
1. 队列数据结构: 消息队列
1. 分页查询:lrange
<a name="xCu1K"></a>
# Set
sadd 添加<br />spop 随机删除<br />srandmember 随机取出<br />scard 统计个数<br />sdiff k1 k2 从第一个减去其他的集合<br />sinter k1 k2 取得交集,都有元素<br />sunion k1 k2 取并集,将所有不同的元素合并<br />sdiffstore sinterstore sunionstore 将计算出的结果存入新的集合<br />smove 原始集合 目标集合 元素 移动到另一个集合中<br />sismember 判断是否在集合中
<a name="JyaPD"></a>
## 使用场景
1. 社交网络:共同好友,共同关注,共同爱好....
1. 唯一计数器:去重特性
1. 标签:
1. 点赞、投票
1. 随机点名
<a name="5mGOF"></a>
# SortedSet
zadd 元素需要一个分数 zadd products 1000 wahaha 300 cokecola 299 pepsicola<br />zrange 默认升序排序<br />zrevrange 默认降序 zrevrange products 0 3<br />zrangebyscore 返回分数,升序<br />zrevrangebyscore 返回分数,降序<br />zcount products 300 10000 分数在区间范围内的数量<br />zrank products cokecola 排名<br />zscore products wahaha 得到对应的分数
<a name="R1kVU"></a>
## 使用场景
- 排行榜
- 时间线,将时间转换为毫秒,按时间排序
<a name="CAQFH"></a>
# Redis使用规范
[https://developer.aliyun.com/article/531067](https://developer.aliyun.com/article/531067)
keys \flushall \config 不能使用<br />vim /etc/redis.conf
```bash
rename-command flushall ""
rename-command flushdb ""
rename-command keys ""
Scan
SCAN cursor [MATCH pattern] [COUNT count]
cursor 游标,特殊游标0表示开始迭代
match 匹配规则, glob风格(=所有,?=单个字符…)
count 限制最大返回数量
循环按批取出所有数据
scan 0 match user: count 10
返回两个元素的数组,第一个元素是下一次迭代的游标 第二元素是本次迭代的数据
下一次迭代时用 上一次的游标;当游标再次返回0时,表示迭代结束
full iteration :以 0 作为游标开始一次新的迭代, 一直调用 SCAN 命令, 直到命令返回游标 0 , 我们称这个过程为一次完整遍历。
127.0.0.1:6379> set user:cyx:energy low
OK
127.0.0.1:6379> set user:zzq:energy low
OK
127.0.0.1:6379> set user:fg:energy 0
OK
127.0.0.1:6379> set user:djx:energy low
OK
127.0.0.1:6379> set user:yxd:energy high
OK
127.0.0.1:6379> set a b
OK
127.0.0.1:6379> set c d
OK
127.0.0.1:6379> scan 0 match user:* count 10
1) "0"
2) 1) "user:fg:energy"
2) "user:yxd:energy"
3) "user:djx:energy"
4) "user:cyx:energy"
5) "user:zzq:energy"
127.0.0.1:6379> scan 0 match user:* count 3
1) "6"
2) 1) "user:fg:energy"
2) "user:yxd:energy"
127.0.0.1:6379> scan 6 match user:* count 3
1) "7"
2) 1) "user:djx:energy"
2) "user:cyx:energy"
3) "user:zzq:energy"
127.0.0.1:6379> scan 7 match user:* count 3
1) "0"
2) (empty list or set)
127.0.0.1:6379> scan 6 match user:* count 3
1) "7"
2) 1) "user:djx:energy"
2) "user:cyx:energy"
3) "user:zzq:energy"
127.0.0.1:6379> scan 7 match user:* count 3
1) "0"
2) (empty list or set)
127.0.0.1:6379> scan 7 match user:* count 2
1) "0"
2) (empty list or set)
127.0.0.1:6379> scan 0 match user:* count 2
1) "2"
2) 1) "user:fg:energy"
127.0.0.1:6379> scan 2 match user:* count 2
1) "1"
2) 1) "user:yxd:energy"
127.0.0.1:6379> scan 1 match user:* count 2
1) "7"
2) 1) "user:djx:energy"
2) "user:cyx:energy"
3) "user:zzq:energy"
127.0.0.1:6379> scan 7 match user:* count 2
1) "0"
2) (empty list or set)
127.0.0.1:6379> sadd stus wangyang tangxiao xiongwei suhaoran yuexiaodong liuyouli chenyang dingyi
(integer) 8
127.0.0.1:6379> sscan stus 0
1) "0"
2) 1) "yuexiaodong"
2) "liuyouli"
3) "dingyi"
4) "xiongwei"
5) "suhaoran"
6) "wangyang"
7) "chenyang"
8) "tangxiao"
127.0.0.1:6379> sscan stus 0 count 3
1) "5"
2) 1) "yuexiaodong"
2) "liuyouli"
3) "dingyi"
4) "xiongwei"
5) "suhaoran"
127.0.0.1:6379> sscan stus 5 count 3
1) "0"
2) 1) "wangyang"
2) "chenyang"
3) "tangxiao"
127.0.0.1:6379>
Java连接Redis
1. Jedis 基础驱动
建的maven的quickstart项目,加依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.1</version>
</dependency>
编码 ```java package com.woniuxy.redis;
import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool;
/**
Hello world! / public class App { public static void main( String[] args ) {
//建立链接
JedisPool jedisPool = new JedisPool("localhost", 6379);
Jedis jedis = jedisPool.getResource();
//发送指令
if(!jedis.exists("stus")) {
jedis.sadd("stus", "邓继鑫", "董海川", "丁懿", "陈扬", "刘又溧", "程昱翔", "杨林", "白秋洋", "田杰仁", "乐小东", "傅刚", "彭淘沿", "胡启昊", "黄小渝", "杜罗乐", "栗浩然", "谭宪军", "黄煜", "熊威", "彭亿元", "周橘恒", "熊春林", "唐肖", "周友强", "朱志强", "黄广", "王阳", "彭章明", "杨文", "甘可可", "徐阳", "彭川弋", "严川", "廖松", "汪界行");
}
String theOne = jedis.srandmember("stus");
System.out.println("天之骄子:"+theOne);
//清理关闭
jedis.close();
jedisPool.close();
} }
<a name="ZMMB9"></a>
## 2. spring-data-redis 高级封装
[https://spring.io/projects/spring-data-redis](https://spring.io/projects/spring-data-redis)<br />1. 建项目 选择 spring-web lombok spring-data-redis<br />2.编码
- RedisTemplate
- opsForXXX 针对于XXX类型的操作
- boundXXXOps
```java
package com.woniuxy.redis.redisbootdemo.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Set;
@RestController
@Slf4j
public class StudentController {
@Autowired
private RedisTemplate redisTemplate;
@GetMapping("dm")
public String callTheRoll() {
//String操作
ValueOperations ops = redisTemplate.opsForValue();
ops.set("qbzs", "cyx");
// ops.setIfAbsent();//如果不存在,则设置 set NX
// ops.setIfPresent()//如果存在,则设置 set XX
//Hash操作
HashOperations hashOps = redisTemplate.opsForHash();
//hset user:1 age 23
hashOps.put("user:1", "age", 23);
//Set操作
SetOperations setOps = redisTemplate.opsForSet();
if(!redisTemplate.hasKey("stusboot")){
setOps.add("stusboot", "邓继鑫", "董海川", "丁懿", "陈扬", "刘又溧", "程昱翔", "杨林", "白秋洋", "田杰仁", "乐小东", "傅刚", "彭淘沿", "胡启昊", "黄小渝", "杜罗乐", "栗浩然", "谭宪军", "黄煜", "熊威", "彭亿元", "周橘恒", "熊春林", "唐肖", "周友强", "朱志强", "黄广", "王阳", "彭章明", "杨文", "甘可可", "徐阳", "彭川弋", "严川", "廖松", "汪界行");
}
Object theOne = setOps.randomMember("stusboot");
log.info("天之骄子 : {}",theOne);
//boundXXXOps 绑定一个KEY,后续操作无须带key
BoundZSetOperations zSetOps = redisTemplate.boundZSetOps("products");
zSetOps.add("wahaha",1000);
zSetOps.add("tianfukele",200);
zSetOps.add("jianlibao",300);
Set set = zSetOps.reverseRange(0, zSetOps.size());
log.info("排名情况:{}",set);
return "天之骄子 :"+theOne;
}
}
作业
- 整理笔记
- 完成以下redis题