Redis
简介
Redis全称为 Remote Dictionary Server,表示远程字典服务器,是跨平台的非关系型数据库。Redis 是一个开源的使用键值对(Key-Value)存储数据库,也是一种NoSQL数据库。(总结:Redis是一个基于内存的高性能非关系型Key-Value数据库。)
NoSQL,指的是非关系型的数据库。NoSQL有时也称作Not Only SQL的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称。
NoSQL用于超大规模数据的存储。(例如谷歌或Facebook每天为他们的用户收集万亿比特的数据)。这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展。
功能
- 可以用于存储用户的登陆信息和认证信息(单点登录 SSO,在分布式系统中的任一一台服务器登录,访问其他的服务器均不需要再进行登录)
- Redis中最大的功能可能就是做系统数据的缓存(这是这个时代的一个技术特点)
- 可以用来做秒杀系统
- 用来存储一些可以容忍丢失的数据
因为Redis本身是基于内存的,怎么都有可能存在数据丢失的风险,所以Redis的适用场景,一定是对数据要求 不严格的地方,比如:评论数、点赞数、最热商品 - 接口的防刷和限流
RESP协议
Redis 的客户端和服务端之间采取了一种名为 Redis序列化的协议(REdis Serialization Protocol,简称RESP),是基于 TCP 的应用层协议 ,RESP 底层采用的是 TCP 的连接方式,通过 TCP 进行数据传输,然后根据解析规则解析相应信息。
在RESP协议中,数据的类型取决于第一个字节:
- +开始表示单行字符串
- -开始表示错误类型
- :开始表示整数
- $开始表示多行字符串
- *开始表示数组
在RESP协议中,构成协议的每一部分必须使用\r\n作为结束符
示例:
SET key value
*3\r\n #3表示这个命令由3部分组成
$3\r\n # 第一部分的长度是3
SET\r\n # 第一部分的内容
$3\r\n # 第二部分的长度是3
key\r\n # 第二部分的内容
$5\r\n # 第三部分的长度是5
value\r\n # 第三部分的内容
Redis命令
1.通用命令
del key #删除键
exists key #检测键是否存在,1-表示存在,0-表示不存在
expire key seconds #为键设置过期时间 单位是秒
pexpire key milliSeconds #为键设置过期时间 单位是毫秒
keys pattern #使用正则表达式查找键,尽量不要使用这个名来来查找,这个名来查找时可能会造成服务器卡顿
persist key #持久化键,过期时间就相当于没有了
ttl key #获取键的剩余过期时间 单位是秒
pttl key #获取键的剩余过期时间 单位是毫秒
type key #获取键的存储的值的类型
select 0~15 #选择操作的库
move key db #移动键到另外一个库中
flushdb #清空当前所在的数据库
flushall #清空全部数据库
dbsize #查看当前数据库中有多少个键
lastsave #查看最后一次操作的时间
monitor #实时监控Redis服务接收到的命令
2.String命令
set key value #设置键的值,如果存在就是修改,不存在就是增加
get key #获取键的值
mset key value[key value ...] #批量设置键的值
mget key [key ...] #批量获取键的值
setex key seconds value #设置键的值,同时设置键的过期时间
setnx key value #当键不存在时才设置键的值
incr key #将键存储的值增加1,只有存储数字的时候有效
incrby key increment #将键存储的值增加给定的增量,只有存储数字的时候有效
decr key #将键存储的值减去1,只有存储数字的时候有效
decrby key decrement #将键存储的值减少给定减量,只有存储数字的时候有效
append key value #当键存在且存储的值是一个字符串时,将值追加到存储的字符串的末尾
3.Hash命令
string: key --> value
hash: key --> {field:value , field2:value2}
hset key field value #设置键存储的字段和值
hget key field #获取键存储的字段值
hmset key field value[field value ...] #批量设置键的存储的字段和值
hmget key [field ...] #批量获取键存储的字段值
hincrby key field increment #键存储的字段值自增1
hsetnx key field value #不存在字段就添加
hexists key field #检查键存储的字段是否存在
hdel key field [field ...] #批量删除键中存储的字段
hgetall key #获取当前键存储的字段和值
hkeys key #获取当前键存储的所有字段
hvals key #获取当前键存储的所有值
hlen key #获取当前键存储的字段数量
4.List命令
list: key -->[elment1, elment2, …] 是有序的
#存储数据(从左侧插入数据,从右侧插入数据)
lpush key value [value ...]
rpush key value [value ...]
lpushx key value #将一个值插入到已存在的列表头部
rpushx key value #为已存在的列表添加值
lset key index value #通过索引设置列表元素的值
#弹栈方式获取数据(左侧弹出数据,从右侧弹出数据)
lpop key
rpop key
lrange key start stop #获取列表指定范围内的元素 -1表示末尾
lindex key index #获取指定索引位置的数据
llen key #获取列表的长度
#删除列表中的数据(他是删除当前列表中的count个value值,count > 0从左侧向右侧删除,count < 0从右侧向左侧删除,count == 0删除列表中全部的value)
lrem key count value
#对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。
ltrim key start stop
#将一个列表中最后的一个数据,插入到另外一个列表的头部位置
rpoplpush list1 list2
5.Set命令
set: key --> [elment1, element2] 无序且去重
#存储数据
sadd key member [member ...]
#获取数据(获取全部数据)
smembers key
#随机获取一个数据(获取的同时,移除数据,count默认为1,代表弹出数据的数量)
spop key [count]
#交集(取多个set集合交集)
sinter set1 set2 ...
#并集(获取全部集合中的数据)
sunion set1 set2 ...
#差集(获取多个集合中不一样的数据)
sdiff set1 set2 ...
#删除数据
srem key member [member ...]
#查看当前的set集合中是否包含这个值
sismember key member
6.Zset(Sorted Set) 命令
数据结构:跳跃表
#添加数据(score必须是数值。member不允许重复的。)
zadd key score member [score member ...]
#修改member的分数(如果member是存在于key中的,正常增加分数,如果memeber不存在,这个命令就相当于zadd)
zincrby key increment member
#查看指定的member的分数
zscore key member
#获取zset中数据的数量
zcard key
#根据score的范围查询member数量
zcount key min max
#删除zset中的成员
zrem key member [member...]
#根据分数从小到大排序,获取指定范围内的数据(withscores如果添加这个参数,那么会返回member对应的分数)
zrange key start stop [withscores]
#根据分数从大到小排序,获取指定范围内的数据(withscores如果添加这个参数,那么会返回member对应的分数)
zrevrange key start stop [withscores]
#根据分数的返回去获取member(withscores代表同时返回score,添加limit,就和MySQL中一样,如果不希望等于min或者max的值被查询出来可以采用 ‘(分数’ 相当于 < 但是不等于的方式,最大值和最小值使用+inf和-inf来标识)
zrangebyscore key min max [withscores] [limit offset count]
#根据分数的返回去获取member(withscores代表同时返回score,添加limit,就和MySQL中一样)
zrevrangebyscore key max min [withscores] [limit offset count]
Java操作Redis
依赖
<dependencies>
<!-- jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
</dependencies>
操作
redis中的操作命令
public class GenericCommandTest {
public static void main(String[] args) throws InterruptedException {
Jedis jedis = new Jedis("localhost", 6379);
if (jedis.exists("name")) {
jedis.del("name");
}
jedis.expire("time", 20);
while (true){
Long rest = jedis.ttl("time");
if(rest == -2) break;
System.out.println(rest);
Thread.sleep(1000);
}
}
}
SCAN操作
SCAN操作可以根据提供的匹配方式和扫描数量来进行扫描,但是每次扫描的结果不一定与扫描数量匹配,只是返回一个在扫描数量范围左右的结果。可能比扫描数量多也可能少。
@Test
public void scan(){
Jedis jedis = new Jedis("localhost", 6379);
jedis.select(0);
jedis.flushDB();
jedis.mset("name","张三","age","20","address","四川成都","phone","18912345678","class","BigDataManage");
//scan 就是扫描 扫描需要配置扫描的条件 这个条件就是ScanParams
ScanParams params = new ScanParams().match("*a*").count(3);
//这个静态变量标识的就是光标开始的位置,默认是0
String cursor = ScanParams.SCAN_POINTER_START;
do {
//扫描后会得到扫描的结果ScanResult
ScanResult<String> scanResult = jedis.scan(cursor,params);
List<String> result = scanResult.getResult();
result.forEach(System.out::println);
System.out.println("=====================================");
cursor = scanResult.getStringCursor();
//当光标位置再次归0 表示扫描完成
} while (!ScanParams.SCAN_POINTER_START.equals(cursor));
jedis.close();
}
@Test
public void hscan(){
Jedis jedis = new Jedis("localhost"