Redis(二)数据类型

一、String

redis中没有使用C语言的字符串表示,而是自定义一个数据结构叫SDS (simple dynamic string)即简单动态字符串。

c语言对字符串的存储是使用字符数组,遇到'\0'字符则认为字符串结束,redis的字符串可以存储任何类型的数据,因为任何类型数据都可以表示成二进制,sds结构中的char buf[]就是存储了二进制数据

redis的字符串是二进制安全的,什么是二进制安全?简单理解就是存入什么数据取出的还是什么数据。redis中的sds不像c语言处理字符串那样遇到'\0'字符则认证字符串结束,它不会对存储进去的二进制数据进行处理,存入什么数据取出还是什么数据。

1.命令

1.1Linux命令
bash 复制代码
# 赋值取值
SET key value
GET key
#向尾部追加值,如果键不存在则将该键的值设置为value
APPEND key value
#获取键值的长度
STRLEN key
#同时设置/获取多个键值
MSET key value [key value ...]
mset k1 v1 k2 v2 k3 v3
MGET key [key ...]
mget k1 k3
1.2RedisTemplate的命令
java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@RestController
public class RedisStringController {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @GetMapping("/redis-string-demo")
    public String demo() {
        // 1. SET key value,设置过期时间
        redisTemplate.opsForValue().set("name", "张三", 3600, TimeUnit.SECONDS);

        // 2. GET key
        String name = (String) redisTemplate.opsForValue().get("name");
        System.out.println("GET name: " + name);

        // 3. APPEND key value
        redisTemplate.opsForValue().set("msg", "hello");
        Long appendLength = redisTemplate.opsForValue().append("msg", " world");
        System.out.println("APPEND后长度:" + appendLength); // 11
        String msg = (String) redisTemplate.opsForValue().get("msg");
        System.out.println("APPEND后msg:" + msg); // hello world

        // 4. STRLEN key
        Long msgLength = redisTemplate.opsForValue().size("msg");
        System.out.println("STRLEN msg: " + msgLength); // 11

        // 5. MSET 批量赋值
        Map<String, Object> multiMap = new HashMap<>();
        multiMap.put("k1", "v1");
        multiMap.put("k2", "v2");
        multiMap.put("k3", "v3");
        redisTemplate.opsForValue().multiSet(multiMap);

        // 6. MGET 批量取值
        List<String> keys = Arrays.asList("k1", "k3");
        List<Object> multiValues = redisTemplate.opsForValue().multiGet(keys);
        System.out.println("MGET k1 k3: " + multiValues); // [v1, v3]

        return "操作完成,控制台查看结果";
    }
}

二、Hash

hash叫散列类型,它提供了字段和字段值的映射。字段值只能是字符串类型 ,不支持散列类型、集合类型等其它类型。

1.赋值与取值

1.1Linux命令
bash 复制代码
HSET key field value	一次只能设置一个字段值
HGET key field			一次只能获取一个字段值
HMSET key field value [field value ...]		一次可以设置多个字段值
HMGET key field [field ...]				一次可以获取多个字段值
HGETALL key
bash 复制代码
127.0.0.1:6379> hset user username zhangsan 
(integer) 1
127.0.0.1:6379> hget user username
"zhangsan"
127.0.0.1:6379> hmset user age 20 username lisi 
OK
127.0.0.1:6379> hmget user age username
1) "20"
2) "lisi"
127.0.0.1:6379> hgetall user
1) "age"
2) "20"
3) "username"
4) "lisi"

HSET命令不区分插入和更新操作,当执行插入操作时HSET命令返回1,当执行更新操作时返回0.

1.2RedisTemplate的命令
java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

@RestController
public class RedisHashController {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @GetMapping("/redis-hash-demo")
    public String hashDemo() {
        // 1. HSET:设置单个字段
        redisTemplate.opsForHash().put("user:1", "name", "张三");

        // 2. HGET:获取单个字段
        String name = (String) redisTemplate.opsForHash().get("user:1", "name");
        System.out.println("HGET user:1 name → " + name); // 张三

        // 3. HMSET:批量设置字段
        Map<String, Object> fieldMap = new HashMap<>();
        fieldMap.put("age", 20);
        fieldMap.put("gender", "男");
        fieldMap.put("phone", "13800138000");
        redisTemplate.opsForHash().putAll("user:1", fieldMap);

        // 4. HMGET:批量获取字段
        List<String> queryFields = Arrays.asList("name", "age", "phone", "email"); // email不存在
        List<Object> multiValues = redisTemplate.opsForHash().multiGet("user:1", queryFields);
        System.out.println("HMGET user:1 name age phone email → " + multiValues); // [张三, 20, 13800138000, null]

        // 5. HGETALL:获取所有字段和值
        Map<Object, Object> allFields = redisTemplate.opsForHash().entries("user:1");
        System.out.println("HGETALL user:1 → " + allFields);
        // 输出:{name=张三, age=20, gender=男, phone=13800138000}

        // 拓展:获取所有字段名/值
        Set<Object> fieldNames = redisTemplate.opsForHash().keys("user:1");
        List<Object> fieldValues = redisTemplate.opsForHash().values("user:1");
        System.out.println("所有字段名 → " + fieldNames); // [name, age, gender, phone]
        System.out.println("所有字段值 → " + fieldValues); // [张三, 20, 男, 13800138000]

        return "Hash操作完成,控制台查看结果";
    }
}

2.判断字段是否存在

2.1Linux命令
bash 复制代码
HEXISTS key field
127.0.0.1:6379> hexists user age		查看user中是否有age字段
(integer) 1
127.0.0.1:6379> hexists user name	查看user中是否有name字段
(integer) 0
bash 复制代码
HSETNX key field value

当字段不存在时赋值,类似HSET,区别在于如果字段已经存在,该命令不执行任何操作。

2.2RedisTemplate的命令
java 复制代码
boolean hasAge = redisTemplate.opsForHash().hasKey("user", "age");
boolean setAge = redisTemplate.opsForHash().putIfAbsent("user", "age", 30);

3.删除字段

可以删除一个或多个字段,返回值是被删除的字段个数

3.1Linux命令
bash 复制代码
HDEL key field [field ...]
127.0.0.1:6379> hdel user age
(integer) 1
127.0.0.1:6379> hdel user age name
(integer) 0
127.0.0.1:6379> hdel user age username
(integer) 1 
3.2RedisTemplate的命令
java 复制代码
//@return 被删除的字段个数
 // 1. 删除单个字段:对应 hdel user age
        long deleteCount1 = deleteHashFields(key, "age");
  // 2. 删除多个字段:对应 hdel user age name
        long deleteCount2 = deleteHashFields(key, "age", "name");     

4.只获取字段名或字段值

4.1Linux命令
bash 复制代码
HKEYS key
HVALS key
127.0.0.1:6379> hmset user age 20 name lisi 
OK
127.0.0.1:6379> hkeys user
1) "age"
2) "name"
127.0.0.1:6379> hvals user
1) "20"
2) "lisi"
4.2RedisTemplate的命令
java 复制代码
redisTemplate.opsForHash().keys("user");
redisTemplate.opsForHash().values("user");

5.获取字段数量

5.1Linux命令
bash 复制代码
HLEN key
127.0.0.1:6379> hlen user
(integer) 2
5.2RedisTemplate的命令
java 复制代码
redisTemplate.opsForHash().size("user");

三、list

列表类型(list)可以存储一个有序的字符串列表 ,常用的操作是向列表两端添加元素,或者获得列表的某一个片段。

列表类型内部是使用双向链表(double linked list)实现的,所以向列表两端添加元素的时间复杂度为0(1),获取越接近两端的元素速度就越快。

1.向列表两端增加元素

1.1Linux命令
bash 复制代码
LPUSH key value [value ...]
RPUSH key value [value ...]
#向列表左边增加元素 
127.0.0.1:6379> lpush list:1 1 2 3
(integer) 3
#向列表右边增加元素 
127.0.0.1:6379> rpush list:1 4 5 6
(integer) 3
1.2RedisTemplate的命令
java 复制代码
redisTemplate.opsForList().leftPushAll("list:1",1,2,3);
redisTemplate.opsForList().rightPushAll("list:1",4,5,6);

2. 从列表两端弹出元素

2.1Linux命令
bash 复制代码
LPOP key
RPOP key
#LPOP命令从列表左边弹出一个元素,会分两步完成,第一步是将列表左边的元素从列表中移除,第二步是返回被移除的元素值。 
127.0.0.1:6379> lpop list:1
"3"
127.0.0.1:6379> rpop list:1
"6"
2.2RedisTemplate的命令
java 复制代码
redisTemplate.opsForList().leftPop("list:1")
redisTemplate.opsForList().rightPop("list:1");

3.获取列表中元素的个数

3.1Linux命令
bash 复制代码
LLEN key
127.0.0.1:6379> llen list:1
(integer) 2
3.2RedisTemplate的命令
java 复制代码
redisTemplate.opsForList().size("list:1")

4.获取列表片段

4.1Linux命令
bash 复制代码
LRANGE key start stop
#LRANGE命令是列表类型最常用的命令之一,获取列表中的某一片段,将返回start、stop之间的所有元素(包含两端的元素),索引从0开始。索引可以是负数,如:"-1"代表最后边的一个元素。 
127.0.0.1:6379> lrange list:1 0 2
1) "2"
2) "1"
3) "4"
4.2RedisTemplate的命令
java 复制代码
redisTemplate.opsForList().range("list:1",0,2);

5.删除列表中指定的值

5.1Linux命令

LREM key count value

LREM命令会删除列表中前count个值为value的元素,返回实际删除的元素个数。根据count值的不同,该命令的执行方式会有所不同:

 当count>0时, LREM会从列表左边开始删除。

 当count<0时, LREM会从列表后边开始删除。

 当count=0时, LREM删除所有值为value的元素。

5.2RedisTemplate的命令
java 复制代码
//从左面删除两个值为2的
redisTemplate.opsForList().remove("list:1",2,2);
//删除右边1个值为4的元素 → count=-1
redisTemplate.opsForList().remove("list:1",-1,4);
//删除所有值为1的元素 → count=0
redisTemplate.opsForList().remove("list:1",0,1);

6.获得/设置指定索引的元素值

6.1Linux命令
bash 复制代码
LINDEX key index
LSET key index value
127.0.0.1:6379> lindex l:list 2
"1"
127.0.0.1:6379> lset l:list 2 2
OK
127.0.0.1:6379> lrange l:list 0 -1
1) "6"
2) "5"
3) "2"
4) "2"
6.2RedisTemplate的命令
java 复制代码
//index 索引(0开始,负数代表倒数)
redisTemplate.opsForList().index("list:1", 2);
//设置索引2的值为2
redisTemplate.opsForList().set("list:1", 2, 2);

7.只保留列表指定片段,指定范围和LRANGE一致

7.1Linux命令
bash 复制代码
LTRIM key start stop
127.0.0.1:6379> lrange l:list 0 -1
1) "6"
2) "5"
3) "0"
4) "2"
127.0.0.1:6379> ltrim l:list 0 2
OK
127.0.0.1:6379> lrange l:list 0 -1
1) "6"
2) "5"
3) "0"
7.2RedisTemplate的命令
java 复制代码
//保留前3个元素
redisTemplate.opsForList().trim("list:1", 0, 2);

8.向列表中插入元素

8.1Linux命令
bash 复制代码
LINSERT key BEFORE|AFTER pivot value
#该命令首先会在列表中从左到右查找值为pivot的元素,然后根据第二个参数是BEFORE还是AFTER来决定将value插入到该元素的前面还是后面。 
127.0.0.1:6379> lrange list 0 -1
1) "3"
2) "2"
3) "1"
127.0.0.1:6379> linsert list after 3 4
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "3"
2) "4"
3) "2"
4) "1"
8.2RedisTemplate的命令
java 复制代码
//position:枚举值 RedisList.Position.BEFORE(前)/ RedisList.Position.AFTER(后);
redisTemplate.opsForList().insert("list:1", position, pivot, value);

9.将元素从一个列表转移到另一个列表中

9.1Linux命令
bash 复制代码
RPOPLPUSH source destination
127.0.0.1:6379> rpoplpush list newlist 
"1"
127.0.0.1:6379> lrange newlist 0 -1
1) "1"
127.0.0.1:6379> lrange list 0 -1
1) "3"
2) "4"
3) "2" 
9.2RedisTemplate的命令
java 复制代码
//弹出list的最后一个元素(1),插入到newlist左侧
redisTemplate.opsForList().rightPopAndLeftPush("list","newlist");

四、Set

在集合中的每个元素都是不同的,且没有顺序。

1.增加/删除元素

1.1Linux命令
bash 复制代码
SADD key member [member ...]
SREM key member [member ...]
127.0.0.1:6379> sadd set a b c
(integer) 3
127.0.0.1:6379> sadd set a
(integer) 0
127.0.0.1:6379> srem set c d
(integer) 1
1.2RedisTemplate的命令
java 复制代码
redisTemplate.opsForSet().add("set", "a", "b", "c");
redisTemplate.opsForSet().remove("set", "a", "b", "c");

2.获得集合中的所有元素

2.1Linux命令
bash 复制代码
SMEMBERS key
127.0.0.1:6379> smembers set
1) "b"
2) "a"
2.2RedisTemplate的命令
java 复制代码
redisTemplate.opsForSet().members("set");

五、sorted set

在集合类型的基础上有序集合类型为集合中的每个元素都关联一个分数 ,这使得我们不仅可以完成插入、删除和判断元素是否存在在集合中,还能够获得分数最高或最低的前N个元素、获取指定分数范围内的元素等与分数有关的操作。

在某些方面有序集合和列表类型有些相似。

1、二者都是有序的。

2、二者都可以获得某一范围的元素。

但是,二者有着很大区别:

1、列表类型是通过链表实现的,获取靠近两端的数据速度极快,而当元素增多后,访问中间数据的速度会变慢。

2、有序集合类型使用散列表实现 ,所有即使读取位于中间部分的数据也很快。

3、列表中不能简单的调整某个元素的位置,但是有序集合可以(通过更改分数实现)

4、有序集合要比列表类型更耗内存。

5、有序集合按 score 数值大小排序,默认升序,score 相同时,按 member 的字典序排序,而列表是按照插入顺序

1.增加元素

1.1Linux命令

向有序集合中加入一个元素和该元素的分数,如果该元素已经存在则会用新的分数替换原有的分数。返回值是新加入到集合中的元素个数,不包含之前已经存在的元素。

bash 复制代码
ZADD key score member [score member ...]
127.0.0.1:6379> zadd scoreboard 80 zhangsan 89 lisi 94 wangwu 
(integer) 3
127.0.0.1:6379> zadd scoreboard 97 lisi 
(integer) 0
#获取元素的分数 
ZSCORE key member
127.0.0.1:6379> zscore scoreboard lisi 
"97"
1.2RedisTemplate的命令
java 复制代码
redisTemplate.opsForZSet().add(key, member, score);
redisTemplate.opsForZSet().score(key, member);

2.获得排名在某个范围的元素列表

2.1Linux命令
bash 复制代码
#ZRANGE key start stop [WITHSCORES]按照元素分数从小到大的顺序返回索引从start到stop之间的所有元素(包含两端的元素)

127.0.0.1:6379> zrange scoreboard 0 2
1) "zhangsan"
2) "wangwu"
3) "lisi"


#ZREVRANGE key start stop [WITHSCORES]按照元素分数从大到小的顺序返回索引从start到stop之间的所有元素(包含两端的元素)

127.0.0.1:6379> zrevrange scoreboard 0 2
1) " lisi "
2) "wangwu"
3) " zhangsan "

#如果需要获得元素的分数的可以在命令尾部加上WITHSCORES参数 
127.0.0.1:6379> zrange scoreboard 0 1 WITHSCORES
1) "zhangsan"
2) "80"
3) "wangwu"
4) "94"
2.2RedisTemplate的命令
java 复制代码
redisTemplate.opsForZSet().range(key, start, end);
redisTemplate.opsForZSet().reverseRange(key, start, end);
redisTemplate.opsForZSet().rangeWithScores(key, start, end);

3.获得指定分数范围的元素

3.1Linux命令

90 👉 包含 90

(90 👉 不包含 90

LIMIT offset count\]: offset = 1 👉 从第 2 条开始 count = 2 👉 取 2 条 ⚠️ offset 是 从 0 开始计数 的 ```bash #ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count] 127.0.0.1:6379> ZRANGEBYSCORE scoreboard 90 97 WITHSCORES 1) "wangwu" 2) "94" 3) "lisi" 4) "97" 127.0.0.1:6379> ZRANGEBYSCORE scoreboard 90 (97 WITHSCORES 1) "wangwu" 2) "94" 127.0.0.1:6379> ZRANGEBYSCORE scoreboard 70 100 limit 1 2 1) "wangwu" 2) "lisi" ``` ##### 3.2RedisTemplate的命令 ```java public Object getZSetByScoreRange(String key, double min, double max, boolean withScores, boolean isMinOpen, boolean isMaxOpen) { ZSetOperations zSetOps = redisTemplate.opsForZSet(); // 构建分数范围 ScoreRange scoreRange = new ScoreRange(); if (isMinOpen) { scoreRange.gt(min); // 开区间:>min } else { scoreRange.gte(min); // 闭区间:≥min } if (isMaxOpen) { scoreRange.lt(max); // 开区间: ZINCRBY scoreboard 4 lisi "101" #获得集合中元素的数量 #ZCARD key 127.0.0.1:6379> ZCARD scoreboard (integer) 3 #获得指定分数范围内的元素个数 #ZCOUNT key min max 127.0.0.1:6379> ZCOUNT scoreboard 80 90 (integer) 1 ``` ##### 4.2RedisTemplate的命令 ```java redisTemplate.opsForZSet().incrementScore("scoreboard", "lisi", 4.0); redisTemplate.opsForZSet().size("scoreboard"); ``` #### 5.按照排名范围删除元素 ##### 5.1Linux命令 ```bash #删除排名在start和stop区间内的 ZREMRANGEBYRANK key start stop 127.0.0.1:6379> ZREMRANGEBYRANK scoreboard 0 1 (integer) 2 127.0.0.1:6379> ZRANGE scoreboard 0 -1 1) "lisi" ZREMRANGEBYSCORE key min max #按照分数范围删除元素 127.0.0.1:6379> zadd scoreboard 84 zhangsan (integer) 1 127.0.0.1:6379> ZREMRANGEBYSCORE scoreboard 80 100 (integer) 1 ``` ##### 5.2RedisTemplate的命令 ```java redisTemplate.opsForZSet().removeRange(key, 0, 1); RedisTemplate.opsForZSet().removeRangeByScore(key, min, max); ``` #### 6.获取元素的排名 ##### 6.1Linux命令 ```bash ZRANK key member ZREVRANK key member #从小到大 127.0.0.1:6379> ZRANK scoreboard lisi (integer) 0 #从大到小 127.0.0.1:6379> ZREVRANK scoreboard zhangsan (integer) 1 ``` ##### 6.2RedisTemplate的命令 ```java redisTemplate.opsForZSet().rank(key, "lisi"); RedisTemplate.opsForZSet().reverseRank(key, member); ```

相关推荐
数据与后端架构提升之路2 小时前
系统架构设计师常见高频考点总结之数据库
数据库·系统架构
xixingzhe22 小时前
MySQL CDC实现方案
数据库·mysql
tqs_123453 小时前
tcc中的空回滚和悬挂问题
java·数据库
哪里不会点哪里.3 小时前
Spring 事务机制详解:原理、传播行为与失效场景
java·数据库·spring
IT大白3 小时前
8、MySQL相关问题补充
数据库·sql
爪哇天下3 小时前
Mysql实现经纬度距离的排序(粗略的城市排序)
数据库·mysql
独自破碎E3 小时前
MySQL中有哪些日志类型?
数据库·mysql
笨蛋不要掉眼泪3 小时前
Redis核心数据类型与命令
数据库·redis·缓存
小唐同学爱学习4 小时前
短链接修改之写锁
spring boot·redis·后端·mysql