复习

- 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 Mmget 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 判断是否有字段```bash127.0.0.1:6379> hset user:cyx age 23(integer) 1127.0.0.1:6379> hset user:cyx score 1000(integer) 1127.0.0.1:6379> hget user:cyx age"23"127.0.0.1:6379> hgetall user:cyx1) "age"2) "23"3) "score"4) "1000"127.0.0.1:6379> hget user:cyx score"1000"127.0.0.1:6379> hgetall user:cyx1) "age"2) "23"3) "score"4) "1000"127.0.0.1:6379> hmset user:hg age 18 score 1000 hobby codingOK127.0.0.1:6379> hmget user:hg age score hobby1) "18"2) "1000"3) "coding"127.0.0.1:6379> hincrby user:hg age 10(integer) 28127.0.0.1:6379> hincrby user:hg age -5(integer) 23127.0.0.1:6379> hexists user:hg age(integer) 1127.0.0.1:6379> hexists user:hg honor(integer) 0127.0.0.1:6379> hexists user:hg lunch(integer) 0127.0.0.1:6379> hkeys user:hg1) "age"2) "score"3) "hobby"127.0.0.1:6379> hvals user:hg1) "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># Setsadd 添加<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># SortedSetzadd 元素需要一个分数 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```bashrename-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 lowOK127.0.0.1:6379> set user:zzq:energy lowOK127.0.0.1:6379> set user:fg:energy 0OK127.0.0.1:6379> set user:djx:energy lowOK127.0.0.1:6379> set user:yxd:energy highOK127.0.0.1:6379> set a bOK127.0.0.1:6379> set c dOK127.0.0.1:6379> scan 0 match user:* count 101) "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 31) "6"2) 1) "user:fg:energy"2) "user:yxd:energy"127.0.0.1:6379> scan 6 match user:* count 31) "7"2) 1) "user:djx:energy"2) "user:cyx:energy"3) "user:zzq:energy"127.0.0.1:6379> scan 7 match user:* count 31) "0"2) (empty list or set)127.0.0.1:6379> scan 6 match user:* count 31) "7"2) 1) "user:djx:energy"2) "user:cyx:energy"3) "user:zzq:energy"127.0.0.1:6379> scan 7 match user:* count 31) "0"2) (empty list or set)127.0.0.1:6379> scan 7 match user:* count 21) "0"2) (empty list or set)127.0.0.1:6379> scan 0 match user:* count 21) "2"2) 1) "user:fg:energy"127.0.0.1:6379> scan 2 match user:* count 21) "1"2) 1) "user:yxd:energy"127.0.0.1:6379> scan 1 match user:* count 21) "7"2) 1) "user:djx:energy"2) "user:cyx:energy"3) "user:zzq:energy"127.0.0.1:6379> scan 7 match user:* count 21) "0"2) (empty list or set)127.0.0.1:6379> sadd stus wangyang tangxiao xiongwei suhaoran yuexiaodong liuyouli chenyang dingyi(integer) 8127.0.0.1:6379> sscan stus 01) "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 31) "5"2) 1) "yuexiaodong"2) "liuyouli"3) "dingyi"4) "xiongwei"5) "suhaoran"127.0.0.1:6379> sscan stus 5 count 31) "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```javapackage 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@Slf4jpublic class StudentController {@Autowiredprivate 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 23hashOps.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,后续操作无须带keyBoundZSetOperations 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题
