Redis

1、Redis是什么?

非关系型数据库,以键值对(key-value)形式存储数据,也是一种NoSQL数据库
NoSQL可用于超大规模数据存储
image.png

2、有了Map为什么还需要Redis?

  • Map是Java提供的,是存在于虚拟机中的,所以是有大小限制的,不能存储大量数据
  • Map不能进行横向扩展和纵向扩展,但是Redis可以,并且Redis支持集群模式
  • Redis的读写速度很快
  • Redis支持多种持久化
  • Redis支持多种数据类型(字符串、哈希、列表、集合、有序集合…)
  • Redis支持多种数据淘汰策略(LRU算法、LFU 算法、随机、ttl、noeviction)

3、Redis能干嘛?

  • 可以存储用户的登录信息和认证信息
  • 系统的数据缓存(高速缓存)
  • 秒杀系统
  • 可以存储一些容忍丢失的数据
  • 接口防刷和限流

4、RESP协议

REdis Serialization Protocol,简称RESP
RESP是基于TCP传输的应用层协议,底层采用TCP传输
在RESP协议中,数据的类型取决于第一个字符:

  • +:单行字符串
  • -:表示错误的类型
  • *::表示整数
  • $:表示多行字符
  • *:表示数组
    在RESP协议中,构成协议的每一部分必须使用\r\n作为结束符
    示例:
set key value

*3\r\n        表示这个命令由三部分组成
$3\r\n        表示第一部分长度为3
set\r\n       表示第一部分的内容
$3\r\n        表示第二部分长度为3
key\r\n       表示第二部分的内容
$5\r\n        表示第三部分长度为35
value\r\n     表示第三部分的内容

5、通用命令

del key //删除一个键

exists key //是否存在一个键

expire key seconds //为一个键设置过期时间、单位秒

pexpire key millionSeconds //为一个键设置过期时间、单位毫秒

ttl key //查看键的剩余过期时间,单位秒

pttl key //查看键的过期时间,单位毫秒

keys * //查看所有的键

persist key //持久化键,相当于永不过期

type key //查看键的类型

select 0~15 //选择0~15之间的一个数据库

move key db //将一个键移动到另一个数据库中

flushdb //刷新数据库

dbsize //查看当前数据库中键的数量(当前数据库的大小)

lastsave //查看最近一次操作时间,时间戳

monitor //实时监控Redis接收到的命令

6、字符串命令

字符串(string)是Redis中的一种基本数据类型

set key value //为键设置一个值,如果存在就是修改,不存在就是添加

get key //获取一个键的值

mset key1 value1 key2 value2... //同时为多个键设置值

mget key1 key2 key3... //同时获取多个键的值

setex key seconds value //设置键的值,同时设置过期时间,单位秒

setnx key value //如果不存在键就为其设置值,如果存在就返回0,不改变原来的值

incr key //为整数键自增1

incrby key increment //指定键增加increment增量

decr key //为整数键自减1

decrby key increment //指定键减少increment增量

append key value //将value追加到指定key的末尾

7、Hash命令

Hash也是Redis中的一种基本数据类型

hset key field value //为键设置字段和值

hget key field //获取键中的字段值

hmset key field1 value1 field2 value2... //同时为键的多个字段设置值

hmget key field1 field2 filed3... //同时获取键中多个字段的值

hincrby key field increment //为键的字段设置增量

hsetnx key field value //不存在就添加字段和值

hexists key field //检查键中是否存在字段

hdel key field1 field2 ... //删除键中的字段

hgetall key //获取键中的所有字段和值

hkeys key //获取键中所有的字段

hvals key //获取键中所有的值

hlen key //获取键中字段的数量

8、List命令

lpush key value1 value2 value3.. //从左往右依次添加值到列表
rpush key value1 value2 value3.. //从右往左依次添加值到列表

lpushx key value //添加一个值到列表的头部
rpushx key value //添加一个值到列表的尾部

lpop key //从列表的尾部弹出一个值
rpop key //从列表的头部弹出一个值

lrange key start stop //从下标为start到下标为stop为列表进行切片,stop为-1表示最后一个

lindex key index //通过下标index取出列表中对用的值

llen key //获取列表的长度

lrem key count value //从列表中删除指定count数量的value,count>0代表从左往右依次寻找,count<0代表从右往左依次寻找,count==0代表全部删除

ltrim key start stop //对从下标start到stop区间的数据进行修剪,不在范围内的数据将会被删除

rpoplpush key1 key2 //从一个列表的尾部弹出一个值添加到另一个列表的头部

9、Set命令

使用场景:黑白名单、

sadd key member1 member2 ... //向set中添加成员

smembers key //获取set中所有的成员

spop key count //随机获取set中count数量(不写为1)的成员

sinter set1 set2 ... //获取set1和set2的交集

sunion set1 set2 ... //获取set1和set2的并集

sdiff set1 set2 ... //获取set1和set2的差集(以set顺序为准)

srem key member1 member2 ... //从set中删除指定的成员,不存在返回0

sismember key member //判断一个成员是否在set中,存在返回1,不存在返回0

10、Zset

使用场景:排行

zadd key score1 member1 score2 member2... //添加key设置成员及其分数

zincrby key increment member //为成员的分数设置增量(增量可以为正数或者负数)

zscore key member //获取成员的分数

zcard key //查看key中成员数量

zcount key min max //查找min到max范围的成员

zrem key member1 member2 ... //删除成员

zrange key start stop [withscores] //从下标start到stop根据分数对成员进行顺序排序

zrevrange key start stop [withscores] //从下标start到stop根据分数对成员进行倒序排序

zrangebyscore key min max [withscores] [limit offset count] //指定最小值到最大值区间内的成员进行顺序排序

zrevrangebyscore key max min [withscores] [limit offset count] //指定最大值到最小值区间内的成员进行逆序排序

11、Java连接redis

11.1、使用Socket与Redis交互

由于Redis的底层使用的是tcp传输,则可以通过Socket编程实现Java与Redis进行交互

[!note]
中文乱码未解决

public class RedisTest {
     
  
    public static void main(String[] args) throws IOException {
     
  
  
       // 创建Socket连接  
       Socket socket = new Socket("localhost", 6379);  
       OutputStream out = socket.getOutputStream();  
       InputStream in = socket.getInputStream();  
  
       // 构建Redis命令  
       String[] commands = {
   "set", "name", "liuxu"};  
  
       // 组装命令  
       StringBuilder sb = new StringBuilder();  
       int cc_len = commands.length;  
       sb.append("*").append(cc_len).append("\r\n");  
       for (String command : commands) {
     
          int c_len = command.length();  
          sb.append("$").append(c_len).append("\r\n").append(command).append("\r\n");  
       }  
  
       // 将命令转化为RESP协议字符串  
       String command = sb.toString();  
       System.out.println(command);  
  
       // 发送命令  
       out.write(command.getBytes(StandardCharsets.UTF_8));  
       out.flush();  
  
       // 读取Redis响应  
       byte[] bytes = new byte[1024];  
       int length = in.read(bytes);  
       String response = new String(bytes, 0, length, StandardCharsets.UTF_8);  
  
       // 查询结果  
       String[] split = response.split("\r\n");  
  
       // 存储结果  
       List<Object> list = new ArrayList<>();  
  
       // 匹配开始符号:+ - $ : *  
       String start = String.valueOf(split[0].toCharArray()[0]);  
  
       // 匹配不同结果  
       if (split.length == 1 && !"-".equals(start)) {
     
          list.add(Integer.parseInt(String.valueOf(split[0].toCharArray()[1])));  
       } else if (split.length == 1) {
     
          list.add(split[0]);  
       } else {
     
          list.addAll(Arrays.asList(split).subList(1, split.length));  
       }  
  
       // 处理不同结果  
       Object res;  
       // System.out.println(start);  
       switch (start) {
     
          case "*":// 处理数组  
             res = list.stream().filter(i -> list.size() % 2 == 0).collect(Collectors.toList());  
             System.out.println(res);  
             break;  
          case ":":// 处理数字  
             Optional<Object> num = list.stream().findFirst();  
             res = num.orElse(null);  
             System.out.println(res);  
             break;  
          case "-":// 遇到错误信息  
             String error = list.get(0).toString();  
             throw new RuntimeException(error);  
          case "$":// 处理多行字符串  
             Optional<Object> first = list.stream().findFirst();  
             res = first.orElse(null);  
             System.out.println(res);  
             break;  
          case "+":// 处理单行字符串  
             Optional<Object> str = list.stream().findFirst();  
             res = str.orElse(null);  
             System.out.println(res);  
             break;  
       }  
    }  
}

11.2、使用Jedis

导入依赖

<dependency>  
    <groupId>redis.clients</groupId>  
    <artifactId>jedis</artifactId>  
    <version>5.1.2</version>  
</dependency>

11.2.1、存储字符串

创建一个简单的命令

@Test
public static void set() {
     
    // 1. 连接Redis  
    Jedis jedis = new Jedis("127.0.0.1", 6379);  
    // 2. 操作Redis - 因为Redis的命令是什么,Jedis的方法就是什么  
    jedis.set("name", "李四");  
    // 3. 释放资源  
    jedis.close();  
}

@Test
public static void get(){
     
    // 1. 连接Redis  
    Jedis jedis = new Jedis("127.0.0.1", 6379);  
    // 2. 操作Redis - 因为Redis的命令是什么,Jedis的方法就是什么  
    String s = jedis.get("name");  
    System.out.println(s);  //李四
    // 3. 释放资源  
    jedis.close();  
}

11.2.2、存储字符数组

11.2.3、SCAN 操作

使用命令keys * 来查询所有的键是阻塞的,但是使用scan是非阻塞的

11.2.3.1、字符串的scan
public void scan() {
     
    Jedis jedis = new Jedis("localhost", 6379);  
    String cursor = ScanParams.SCAN_POINTER_START; // 游标,记录的是下标  
    ScanParams params = new ScanParams().match("*a*").count(3); // 参数,对应的是扫描条件  
    do {
     
       ScanResult<String> result = jedis.scan(cursor, params);// 每次扫描的结果集  
       List<String> list = result.getResult();// 从结果集中获取查询的结果  
       list.forEach(System.out::println);  
       cursor = result.getCursor();// 从结果集中获取游标  
       System.out.println(cursor);  
       System.out.println("==========================");  
    } while (!cursor.equals(ScanParams.SCAN_POINTER_START));// 当游标归0的时候代表扫描完成  
    jedis.close();  
}
11.2.3.2、Hash的hscan
public void hscan() {
     
    Jedis jedis = new Jedis("localhost", 6379);  
    String cursor = ScanParams.SCAN_POINTER_START; // 游标,记录的是下标  
    ScanParams params = new ScanParams().match("*a*").count(3); // 参数,对应的是扫描条件  
    do {
     
    //hscan传入的参数: key cursor params
       ScanResult<Map.Entry<String, String>> result = jedis.hscan("hash", cursor, params);// 每次扫描的结果集  
       List<Map.Entry<String, String>> list = result.getResult();// 从结果集中获取查询的结果  
       list.forEach(entry -> System.out.println(entry.getKey() + ":" + entry.getValue()));  
       cursor = result.getCursor();// 从结果集中获取游标  
       // System.out.println(cursor);  
       System.out.println("==========================");  
    } while (!cursor.equals(ScanParams.SCAN_POINTER_START));// 当游标归0的时候代表扫描完成  
    jedis.close();  
}
11.2.3.3、Set的sscan
public void sscan() {
     
    Jedis jedis = new Jedis("localhost", 6379);  
    String cursor = ScanParams.SCAN_POINTER_START; // 游标,记录的是下标  
    ScanParams params = new ScanParams().match
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拖把湛屎,戳谁谁死

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值