Redis 入门

Redis
  • Remote Dictionary Server(远程词典服务器),是一个基于内存的键值型NoSQL(非关系型数据库)
  • 官方文档:https://redis.io/commands/
Redis的特征

键值型,支持多种数据结构
单线程,每个命令具备原子性
低延迟,速度快(基于内存、IO多路复用、良好的编码)
支持数据持久化
支持主从集群、分片集群
支持多语言客户端

Redis数据结构
  • 基本类型:String、Hash、List、Set、SortedSet

  • 特殊类型:GEO、BitMap、HyperLog等

常用命令
查看命令
# 查看group分组下的所有命令
# help @[group] 
127.0.0.1:6379> help @string

# 查看command命令
# help [command]
127.0.0.1:6379> help keys
通用命令
# 查询所有符合模板的 key(由于redis是单线程,当数据量比较大时,查询会消耗大量时间,会阻塞其他命令,所以不建议在生产环境上运行)
# keys pattern
127.0.0.1:6379> keys *
1) "age"
2) "name"
127.0.0.1:6379> keys n*
1) "name"

# 删除一个或多个 key,返回删除的条数
# del key [key ...] 
127.0.0.1:6379> del k1
(integer) 1
127.0.0.1:6379> del k2 k3
(integer) 2

# 查询一个或多个 key 是否存在,返回存在的条数
# exists key [key ...] 
127.0.0.1:6379> exists name age
(integer) 2

# 给一个 key 设置有效期(到期后自动删除该key)
# expire key seconds
127.0.0.1:6379> expire name 5
(integer) 1

# 查询一个 key 剩余有效期(返回值即剩余存活的时间,返回值为 -1 代表永久存活,返回值为 -2 代表已经死亡)
# ttl key
127.0.0.1:6379> ttl name
(integer) 3
127.0.0.1:6379> ttl age
(integer) -1
String类型
  • 其 value 是字符串,根据字符串格式的不同,又能分为3类:

    string:普通字符串
    int:整数类型,可以做自增、自减操作
    float:浮点类型,可以做自增、自减操作

  • 不管是哪种方式,底层都是用字节数组形式存储,只不过是编码方式不同。字符串类型的最大空间不能超过512M

# 添加或修改对应 key 的值
# set key value [ex seconds] [px milliseconds]
127.0.0.1:6379> set name bob
OK
127.0.0.1:6379> set name clarence
OK
127.0.0.1:6379> set name clarence ex 10
OK
127.0.0.1:6379> set name clarence px 10000
OK

# 根据 key 获取string类型的 value
# get key
127.0.0.1:6379> get name
"clarence"

# 批量添加或修改对应 key 的值
# mset key value [key value ...]
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3
OK

# 批量根据 key 获取string类型的 value
# mget key [key ...]
127.0.0.1:6379> mget k1 k2 k3
1) "v1"
2) "v2"
3) "v3"

# 让一个整型的 key 自增 1
# incr key
127.0.0.1:6379> get age
"23"
127.0.0.1:6379> incr age
(integer) 24
127.0.0.1:6379> incr age
(integer) 25
127.0.0.1:6379> get age
"25"

# 让一个整型的 key 自增,并指定增量(increment为负数可实现自减)
# incrby key increment
127.0.0.1:6379> get age
"25"
127.0.0.1:6379> incrby age 2
(integer) 27
127.0.0.1:6379> incrby age 2
(integer) 29
127.0.0.1:6379> incrby age -1
(integer) 28
127.0.0.1:6379> get age
"28"

# 让一个浮点型的 key 自增,并指定增量(increment为负数可实现自减)
# incrbyfloat key increment
127.0.0.1:6379> set score 5.6
OK
127.0.0.1:6379> incrbyfloat score 0.5
"6.1"
127.0.0.1:6379> incrbyfloat score 0.5
"6.6"
127.0.0.1:6379> get score
"6.6"

# 添加一个 string 类型的键值对,前提是这个 key 不存在,否则不执行
# setnx key value
127.0.0.1:6379> setnx name jack
(integer) 0
127.0.0.1:6379> setnx sex male
(integer) 1

# 添加一个 string 类型的键值对,并指定有效期
# setex key seconds value
127.0.0.1:6379> setex name2 10 jack
OK
127.0.0.1:6379> ttl name2
(integer) 6
  • String结构存储对象:将对象序列化为json字符串后存储
    String结构存储对象
Hash类型
  • Hash类型,也叫散列,其 value 是一个无序字典(类似于 Java 中的 HashMap 结构)
  • Hash结构可以将对象中的每个字段独立存储,方便修改对象的单个字段
    Hash结构存储对象
# 添加或修改对应 hash 类型 key 的 field 的值
# hset key field value
127.0.0.1:6379> hset project:user:3 name jack
(integer) 1
127.0.0.1:6379> hset project:user:3 age 25
(integer) 1

# 获取一个 hash 类型 key 的 field 的值
# hget key field
127.0.0.1:6379> hget project:user:3 name
"jack"
127.0.0.1:6379> hget project:user:3 age
"25"

# 批量添加或修改对应 hash 类型 key 的 field 的值
# hmset key field value [field value ...]
127.0.0.1:6379> hmset project:user:4 name mike age 26
OK

# 批量获取多个 hash 类型 key 的 field 的值
# hmget key field [field ...]
127.0.0.1:6379> hmget project:user:4 name age
1) "mike"
2) "26"

# 获取一个 hash 类型 key 的所有 field 和 value 的值
# hgetall key
127.0.0.1:6379> hgetall project:user:3
1) "name"
2) "jack"
3) "age"
4) "25"

# 获取一个 hash 类型 key 的所有 field 的值
# hkeys key
127.0.0.1:6379> hkeys project:user:3
1) "name"
2) "age"

# 获取一个 hash 类型 key 的所有 value 的值
# hvals key
127.0.0.1:6379> hvals project:user:3
1) "jack"
2) "25"

# 让一个 hash 类型 key 的整型 field 值自增,并指定增量(increment为负数可实现自减)
# hincrby key field increment
127.0.0.1:6379> hincrby project:user:3 age 2
(integer) 27

# 添加一个 hash 类型的 key 的 field 值,前提是这个 field 不存在,否则不执行
# hsetnx key field value
127.0.0.1:6379> hsetnx project:user:3 name zhangsan
(integer) 0
127.0.0.1:6379> hsetnx project:user:3 sex male
(integer) 1
List类型
  • Redis 中的 List 类型与 Java 中的 LinkedList 类似,可以看作是一个双向链表结构的队列

  • 特征也与 LinkedList 类似:

    有序
    元素可重复
    插入和删除快
    查询速度一般

  • 常用来存储有序数据

# 在一个列表前添加一个或多个值(从队列左侧(left)插入)
# lpush key value [value ...]
127.0.0.1:6379> lpush ages 10 20 30
(integer) 3

# 在一个列表后添加一个或多个值(从队列右侧(right)插入)
# rpush key value [value ...]
127.0.0.1:6379> rpush ages 40 50 60
(integer) 6

# 从列表中获取下标范围内的所有元素
# lrange key start stop
127.0.0.1:6379> lrange ages 1 4
1) "20"
2) "10"
3) "40"
4) "50"

# 移除并获取列表中的第一个元素,没有则返回 nil(从队列左侧(left)取值)
# lpop key
127.0.0.1:6379> lpop ages
"30"
127.0.0.1:6379> lpop ages
"20"

# 移除并获取列表中的最后一个元素,没有则返回 nil(从队列右侧(right)取值)
# rpop key
127.0.0.1:6379> rpop ages
"60"
127.0.0.1:6379> rpop ages
"50"

# blpop 和 brpop,与 lpop 和 rpop 类似,区别在于没有元素时会等待指定时间,而不是直接返回 nil(从队列取值,没有元素时阻塞(block)指定时间)
# blpop key timeout
# brpop key timeout
# redis-cli 窗口一
127.0.0.1:6379> blpop ages2 60
1) "ages2"
2) "25"
(16.91s)
# redis-cli 窗口二
127.0.0.1:6379> lpush ages2 15 20 25
(integer) 3
Set类型
  • Redis 的 Set 结构与 Java 中的 HashSet 类似,可以看作是一个 value 值为 null 的 HashMap
  • 与 HashSet 相似的特征

    无序
    元素不可重复
    查找快
    支持交集、并集、差集等功能

# 向 set 中添加(add)一个或多个元素
# sadd key member [member ...]
127.0.0.1:6379> sadd set a b c d
(integer) 4

# 移除(remove) set 中指定的一个或多个元素
# srem key member [member ...]
127.0.0.1:6379> srem set a b
(integer) 2

# 判断给定的值是否是 set 的成员(is member)
# sismember key member
127.0.0.1:6379> sismember set a
(integer) 0
127.0.0.1:6379> sismember set c
(integer) 1

# 获取 set 中的元素个数(card)
# scard key
127.0.0.1:6379> scard set
(integer) 2

# 获取 set 中的所有元素(members)
# smembers key
127.0.0.1:6379> smembers set
1) "d"
2) "c"

# 多个 set 的交集(intersect)
# sinter key [key ...]
# 多个 set 与第一个 set 的差集(difference)
# sdiff key [key ...]
# 多个 set 的并集(union)
# sunion key [key ...]
127.0.0.1:6379> sadd set2 a b c
(integer) 3
127.0.0.1:6379> sadd set3 b c d
(integer) 3
127.0.0.1:6379> sinter set2 set3
1) "c"
2) "b"
127.0.0.1:6379> sdiff set2 set3
1) "a"
127.0.0.1:6379> sdiff set3 set2
1) "d"
127.0.0.1:6379> sunion set2 set3
1) "b"
2) "a"
3) "c"
4) "d"
SortedSet类型
  • Redis 的 SortedSet 是一个可排序的 set 集合,类似 Java 中的 TreeSet,但底层数据结构差别却很大

  • SortedSet 中的每一个元素都带有一个 score 属性,可以基于 score 属性对元素排序,底层的实现是一个跳表(SkipList)加 hash 表

  • SortedSet 具备以下特性:

    可排序
    元素不重复
    查询速度快

# 向 sortedSet 中添加(add)一个或多个元素,如果已经存在则更新其 score 值
# zadd key score member [score member ...]
127.0.0.1:6379> zadd class 90 xiaobai 88 xiaohei 94 xiaohui 84 xiaolan 82 xiaolv 99 xiaohong 60 xiaoqing
(integer) 7

# 移除(remove) sortedSet 中的一个或多个元素
# zrem key member [member ...]
127.0.0.1:6379> zrem class xiaoqing
(integer) 1

# 获取 sortedSet 中指定元素的 score 值
# zscore key member
127.0.0.1:6379> zscore class xiaobai
"90"

# 获取 sortedSet 中指定元素的排名(从0开始计数)
# 正序:zrank key member
# 倒序:zrevrank key member
127.0.0.1:6379> zrank class xiaobai
(integer) 3
127.0.0.1:6379> zrevrank class xiaobai
(integer) 2

# 获取 sortedSet 中的元素个数(card)
# zcard key
127.0.0.1:6379> zcard class
(integer) 6

# 统计 sortedSet 中 score 值在指定范围内的元素个数
# zcount key min max
127.0.0.1:6379> zcount class 90 100
(integer) 3

# 让 sortedSet 中的指定值自增,并指定增量(increment为负数可实现自减)
# zincrby key increment member
127.0.0.1:6379> zincrby class 2 xiaobai
"92"
127.0.0.1:6379> zincrby class -1 xiaobai
"91"

# 按照 score 排序后,获取指定排名范围内的元素
# 正序:zrange key start stop
# 倒序:zrevrange key start stop
127.0.0.1:6379> zrange class 0 2
1) "xiaolv"
2) "xiaolan"
3) "xiaohei"
127.0.0.1:6379> zrevrange class 0 2
1) "xiaohong"
2) "xiaohui"
3) "xiaobai"

# 按照 score 排序后,获取指定 score 范围内的元素
# zrangebyscore key min max
127.0.0.1:6379> zrangebyscore class 90 100
1) "xiaobai"
2) "xiaohui"
3) "xiaohong"

# 所有的排名默认都是升序,且序号从0开始,如果要降序排序只需在命令的 z 后面添加 rev 即可(reverse)
# 例:zrank -> zrevrank
Key的层级结构
  • Redis 的 key 允许多个单词直接用 ‘:’ 隔开形成层级结构
# 层级结构
127.0.0.1:6379> set project:user:1 bob
OK
127.0.0.1:6379> set project:user:2 clarence
OK

Key的层级结构

Java 客户端 - Jedis
  • Jedis官网: https://github.com/redis/jedis
  • Jedis 是以 Redis 命令作为方法名称,简单实用,但是Jedis实例是线程不安全的,多线程环境下需要基于线程池来使用
Jedis 的基本使用
  • 引入依赖
<dependencies>
    <!--jedis-->
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>4.2.0</version>
    </dependency>
    <!--单元测试-->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <version>5.7.1</version>
        <scope>test</scope>
    </dependency>
</dependencies>
  • 单元测试 Demo
package com.fc;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import redis.clients.jedis.Connection;
import redis.clients.jedis.JedisPooled;

import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class JedisTest {
    // 默认连接 127.0.0.1:6379
//    JedisPooled jedis = new JedisPooled();
    // 建立连接(有密码的需要设置密码)
//    JedisPooled jedis = new JedisPooled("192.168.198.131", 6379, null, "123456");
    // 建立连接(无密码)
    JedisPooled jedis = new JedisPooled("127.0.0.1", 6379);

    // 另一种创建方式
    private JedisPooled jedis2;

    @BeforeEach
    void beforeTest() {
        GenericObjectPoolConfig<Connection> poolConfig = new GenericObjectPoolConfig<>();
        // 最大连接
        poolConfig.setMaxTotal(8);
        // 最大空闲连接
        poolConfig.setMaxIdle(8);
        // 最小空闲连接
        poolConfig.setMinIdle(0);
        // 最长等待时间
        poolConfig.setMaxWait(Duration.ofSeconds(200));
        // 可以选择使用第几号库
        jedis2 = new JedisPooled(poolConfig, "127.0.0.1", 6379, 1000, null, null, 0);
    }

    // String 类型
    @Test
    public void testString () {
        String result = jedis.set("name", "clarence");
        System.out.println(result);
        String name = jedis.get("name");
        System.out.println(name);
    }

    // Hash 类型
    @Test
    public void testHash () {
        jedis.hset("mydemo:user:1", "name", "clarence");
        jedis.hset("mydemo:user:1", "age", "25");
        Map<String, String> map = jedis.hgetAll("mydemo:user:1");
        System.out.println(map);
    }

    // List 类型
    @Test
    public void testList () {
        jedis.lpush("names", "xiaobai", "xiaohei", "xiaolan");
        List<String> names = jedis.lrange("names", 0, 3);
        System.out.println(names);
    }

    // Set 类型
    @Test
    public void testSet () {
        jedis.sadd("set", "a", "b", "c");
        Set<String> set = jedis.smembers("set");
        System.out.println(set);
    }

    // SortedSet 类型
    @Test
    public void testSortedSet () {
        jedis.zadd("class", 90, "xiaobai");
        List<String> aClass = jedis.zrangeByScore("class", 90, 100);
        System.out.println(aClass);
        Map<String, Double> map = new HashMap<>();
        map.put("xiaohei", 88.0);
        map.put("xiaohui", 94.0);
        map.put("xiaolan", 84.0);
        map.put("xiaolv", 82.0);
        map.put("xiaohong", 99.0);
        jedis.zadd("class", map);
        List<String> aClass1 = jedis.zrange("class", 0, 6);
        System.out.println(aClass1);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

_秋牧

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

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

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

打赏作者

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

抵扣说明:

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

余额充值