存储中间件-Redis

Redis 基础入门

一、为什么用 Redis?

Redis 是用C语言开发的一个把数据放在内存里的键值存储(内存型 Key–Value 存储),读写极快QPS达10万+,常见用途包括:缓存、会话(session)存储、短信验证码、排行榜、限流、简单队列等。它既可以做缓存加速,也能在某些场景下当轻量型数据库来用。


二、下载与安装

2.1 Windows

3.2 Linux

示例流程:使用xshell把 redis-6.x.tar.gz 上传并编译:

cd /usr/local/redis-6.x
make
make install

关键文件解释:

  • redis-server:启动服务的可执行文件
  • redis-cli:命令行客户端
  • redis.conf:配置文件(修改密码、持久化、端口等都在这里)

三、Redis基本使用

3.1 启动

redis-server /path/to/redis.conf

Windows 命令:

redis-server.exe redis.windows.conf

3.2 连接

redis-cli               # 默认连接 localhost:6379
redis-cli -h host -p port -a password

3.3 设置访问密码

redis.conf 中设置:

requirepass 你的密码

修改配置要重启 Redis 才生效。注意:Redis 只有密码,认证方式与MySQL不同。

3.4 Redis客户端图形工具

redis-cli命令行操作及其繁琐,也没有图形化界面,我们使用第三方的redis图形化客户端工具:

Another Redis Desktop Manager-win-1.7

安装完毕后,直接双击启动

新建连接

连接成功

四、Redis 常用数据类型

4.1 String(字符串)

  • 场景:验证码、单值缓存、简单计数器

4.2 Hash(哈希)

  • 场景:对象(用户信息)存储,字段级别读写更方便

4.3 List(列表)

  • 场景:消息队列、时间线(按顺序)、最近记录

4.4 Set(集合)

  • 场景:去重、好友关系、标签集合(支持交集并集差集)

4.5 Sorted Set(有序集合 / ZSet)

  • 场景:排行榜、带权重排序的数据(score 可以是分数、时间戳)

五、常用命令

5.1 字符串

  • SET key value
    示例:

    > SET name jack
    OK
    
  • GET key

    > GET name
    "jack"        # 在 redis-cli 普通输出会显示为:jack(或带双引号,取决客户端)
    > GET noexist
    (nil)
    
  • SETEX key seconds value(设置并指定过期时间)

    > SETEX code 300 1234
    OK
    > TTL code
    (integer) 299
    
  • SETNX key value(仅当 key 不存在时设置)
    第一次设置:

    > SETNX lock 1
    (integer) 1
    

    再次设置:

    > SETNX lock 2
    (integer) 0
    > GET lock
    "1"
    

5.2 哈希命令

  • HSET key field value

    > HSET user:100 name xiaoming
    (integer) 1      # 返回 1 表示新字段被创建;如果是更新字段则返回 0
    > HSET user:100 age 22
    (integer) 1
    
  • HGET key field

    > HGET user:100 name
    "xiaoming"
    > HGET user:100 notexists
    (nil)
    
  • HDEL key field

    > HDEL user:100 name
    (integer) 1      # 返回删除的字段数
    
  • HKEYS key / HVALS key

    > HKEYS user:100
    1) "age"
    2) "name"
    > HVALS user:100
    1) "22"
    2) "xiaoming"
    

5.3 列表命令

  • LPUSH key val1 [val2 ...]

    > LPUSH mylist a b c
    (integer) 3      # 返回列表当前长度(这里是 3)
    
  • LRANGE key start stop

    > LRANGE mylist 0 -1
    1) "c"
    2) "b"
    3) "a"
    
  • RPOP key

    > RPOP mylist
    "a"
    > LLEN mylist
    (integer) 2
    
  • LLEN key

    > LLEN mylist
    (integer) 2
    
  • BRPOP key timeout(阻塞弹出)

    > BRPOP q 5
    1) "q"
    2) "message"
    # 如果超时并且仍无元素则返回 (nil)
    

5.4 集合命令

  • SADD key member1 [member2]

    > SADD set1 a b c d
    (integer) 4
    > SADD set1 a
    (integer) 0   # 重复成员不再被添加
    
  • SMEMBERS key

    > SMEMBERS set1
    1) "d"
    2) "c"
    3) "b"
    4) "a"
    # 注:集合无序,返回顺序不固定
    
  • SCARD key(成员数)

    > SCARD set1
    (integer) 4
    
  • SINTER key1 key2(交集)

    > SADD set2 a b x y
    (integer) 4
    > SINTER set1 set2
    1) "b"
    2) "a"
    
  • SREM key member(移除)

    > SREM set1 a
    (integer) 1
    

5.5 有序集合(ZSet)命令

  • ZADD key score member [score member ...]

    > ZADD zset1 10.0 a 10.5 b
    (integer) 2
    > ZADD zset1 10.2 c
    (integer) 1
    
  • ZRANGE key start stop [WITHSCORES]

    > ZRANGE zset1 0 -1
    1) "a"
    2) "c"
    3) "b"
    > ZRANGE zset1 0 -1 WITHSCORES
    1) "a"
    2) "10"
    3) "c"
    4) "10.199999999999999"
    5) "b"
    6) "10.5"
    
  • ZINCRBY key increment member

    > ZINCRBY zset1 5.0 a
    "15"     # 返回 member 最新的 score(字符串形式)
    
  • ZREM key member

    > ZREM zset1 b
    (integer) 1
    

5.6 通用命令(跨类型)

  • KEYS pattern(慎用,生产环境尽量不用)

    > KEYS *
    1) "set2"
    2) "mylist"
    3) "zset1"
    4) "name"
    5) "key1"
    6) "set1"
    7) "100"
    
  • EXISTS key

    > EXISTS name
    (integer) 1
    > EXISTS noexist
    (integer) 0
    
  • TYPE key

    > TYPE name
    string
    > TYPE set1
    set
    > TYPE mylist
    list
    
  • DEL key [key ...](删除 key)

    > DEL name
    (integer) 1
    > DEL 100 key1
    (integer) 2
    

六、Spring Data Redis

在 Java 中操作 Redis 常用客户端:

  • Jedis:命令映射直观,学习成本低
  • Lettuce:基于 Netty,支持多线程异步/响应式,性能好
  • Spring Data Redis:在 Spring Boot 中最方便,推荐用于企业项目

6.1 Spring Data Redis 使用

Spring Data Redis 是 Spring 的一部分,提供了在 Spring 应用中通过简单的配置就可以访问 Redis 服务,对 Redis 底层开发包进行了高度封装。在 Spring 项目中,可以使用Spring Data Redis来简化 Redis 操作。

网址:https://spring.io/projects/spring-data-redis

  1. 依赖:
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  1. application.yml
spring:
  redis:
    host: localhost
    port: 6379
    password: 123456
    database: 10
  1. 自定义 RedisTemplate 序列化,默认的key序列化器为JdkSerializationRedisSerializer,导致我们存到Redis中后的数据和原始数据有差别,设置为StringRedisSerializer序列化器:
/*
    * redisConnectionFactory:这个连接工厂对象并不需要自己去创建,因为在
    *      server子模块下的pom.xml文件已经引入了starter依赖,这个starter依赖
    *      会自动的把这个连接工厂对象给我们创建好,并且放到Spring容器中,所以这个地方只需要声明一下
    *      就可以把它注入进来了。
    * */
@Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        // 记录创建RedisTemplate对象的日志
        log.info("开始创建redis对象");
        // 实例化RedisTemplate
        RedisTemplate redisTemplate = new RedisTemplate();
        // 设置Redis连接工厂
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // 设置键的序列化方式为StringRedisSerializer,确保键以字符串形式存储
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        // 返回配置好的RedisTemplate实例
        return redisTemplate;
    }
  • 两种序列化的最直接区别
  1. 五种类型api
@SpringBootTest
public class SpringDataRedisTest {
    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void testRedisTemplate(){
        System.out.println(redisTemplate);
        //string数据操作
        ValueOperations valueOperations = redisTemplate.opsForValue();
        //hash类型的数据操作
        HashOperations hashOperations = redisTemplate.opsForHash();
        //list类型的数据操作
        ListOperations listOperations = redisTemplate.opsForList();
        //set类型数据操作
        SetOperations setOperations = redisTemplate.opsForSet();
        //zset类型数据操作
        ZSetOperations zSetOperations = redisTemplate.opsForZSet();
    }

6.2 5种数据类型基本操作

1). 操作字符串类型数据

@Test
    public void testString(){
        // set、 get 、setex、 setnx
        //1.设置指定key的值
        redisTemplate.opsForValue().set("name","小明");
        //2.获取指定key的值,返回的是object对象,可以进行强转
        String city = (String) redisTemplate.opsForValue().get("name");
        System.out.println(city);//小明
        //3.设置指定key的值,并指定 key 的过期时间
        //  参数:k、V、过期时间、单位(TimeUnit.MINUTES分钟,这是枚举类型)
        redisTemplate.opsForValue().set("code","1234",3, TimeUnit.MINUTES);
        //4.只有在 key 不存在时设置 key 的值
        //问题:前面讲过这个set命令操作的value是字符串类型,但是这个地方使用java来操作的时候value变为object类型了?
        // 答: java中调用方法的时候这个value可以是任意类型,最终他都会把这个对象进行一个序列化,最终都会转化成redis中的String来进行存储。
        redisTemplate.opsForValue().setIfAbsent("lock","1"); //第一次没有k成功
        redisTemplate.opsForValue().setIfAbsent("lock","2"); //第二次有k失败
    }

2). 操作哈希类型数据

    @Test
    public void testHash(){
        //hset、 hget、 hdel、 hkeys、 hvals
        HashOperations hashOperations = redisTemplate.opsForHash();
        //1.将哈希表 key 中的字段 field 的值设为 value
        hashOperations.put("100","name","tom");
        hashOperations.put("100","age","20");
        //2.获取存储在哈希表中指定字段的值,返回的是object对象,可以进行强转
        String name = (String) hashOperations.get("100", "name");
        System.out.println(name); //tom
        //3.获取哈希表中所有字段
        Set keys = hashOperations.keys("100");
        System.out.println(keys);//[name, age]
        //4.获取哈希表中所有值
        List values = hashOperations.values("100");
        System.out.println(values);//[tom, 20]
        //5. 删除存储在哈希表中的指定字段
        hashOperations.delete("100","age");
    }

3). 操作列表类型数据

    @Test
    public void testList(){
        //lpush 、lrange 、rpop 、llen
        ListOperations listOperations = redisTemplate.opsForList();
        //1. 将一个或多个值插入到列表头部
        listOperations.leftPushAll("mylist","a","b","c");//一次性插入多个
        listOperations.leftPush("mylist","d");//一次性插入一个
        //2.获取列表指定范围内的元素  0代表从队列头部开始   -1代表队列的尾部
        List mylist = listOperations.range("mylist", 0, -1);
        System.out.println(mylist);//[d, c, b, a]
        //3.移除并获取列表最后一个元素,并且这个命令会返回这个值
        listOperations.rightPop("mylist");
        //4.获取列表长度
        Long size = listOperations.size("mylist");
        System.out.println(size);//3
    }

4). 操作集合类型数据

    @Test
    public void testSet(){
        //sadd、 smembers 、scard 、sinter、 sunion 、srem
        SetOperations setOperations = redisTemplate.opsForSet();
        //1.向集合添加一个或多个成员
        setOperations.add("set1","a","b","c","d");
        setOperations.add("set2","a","b","x","y");
        //2. 返回集合中的所有成员
        Set members = setOperations.members("set1");
        System.out.println(members);//[d, c, b, a]
        //3.获取集合的成员数
        Long size = setOperations.size("set1");
        System.out.println(size);//4
        //4.返回给定所有集合的交集
        Set intersect = setOperations.intersect("set1", "set2");
        System.out.println(intersect);//[b, a]
        //5.返回所有给定集合的并集
        Set union = setOperations.union("set1", "set2");
        System.out.println(union);//[b, a, d, c, y, x]
        //6.移除集合中一个或多个成员
        setOperations.remove("set1","a","b");
    }

5). 操作有序集合类型数据

    @Test
    public void testZset(){
        //zadd 、zrange、 zincrby 、zrem
        ZSetOperations zSetOperations = redisTemplate.opsForZSet();
        //1.向有序集合添加一个或多个成员
        zSetOperations.add("zset1","a",10);
        zSetOperations.add("zset1","b",12);
        zSetOperations.add("zset1","c",9);
        //2.通过索引区间返回有序集合中指定区间内的成员
        Set zset1 = zSetOperations.range("zset1", 0, -1);
        System.out.println(zset1);//[c, a, b]
        //3.有序集合中对指定成员的分数加上增量 increment
        zSetOperations.incrementScore("zset1","c",10);
        //4. 移除有序集合中的一个或多个成员
        zSetOperations.remove("zset1","a","b");
    }

6). 通用命令操作

    @Test
    public void testCommon(){
        //keys 、exists、 type 、del
        //1.查找所有符合给定模式( pattern)的 key
        Set keys = redisTemplate.keys("*");
        System.out.println(keys);//[set2, zset1, set1]
        //2.检查给定 key 是否存在
        Boolean name = redisTemplate.hasKey("name");
        Boolean set1 = redisTemplate.hasKey("set1");
        //3.返回 key 所储存的值的类型
        for (Object key : keys) {
            DataType type = redisTemplate.type(key);
            System.out.println(type.name());//SET  ZSET  SET
        }
        //4.该命令用于在 key 存在是删除 key
        redisTemplate.delete("mylist");
    }

欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1701220998@qq.com
导航页 GitHub