摘要

Redis 主要支持以下几种数据类型:

  • string(字符串): 基本的数据存储单元,可以存储字符串、整数或者浮点数。
  • hash(哈希):一个键值对集合,可以存储多个字段。
  • list(列表):一个简单的列表,可以存储一系列的字符串元素。
  • set(集合):一个无序集合,可以存储不重复的字符串元素。
  • zset(sorted set:有序集合): 类似于集合,但是每个元素都有一个分数(score)与之关联。
  • 位图(Bitmaps):基于字符串类型,可以对每个位进行操作。
  • 超日志(HyperLogLogs):用于基数统计,可以估算集合中的唯一元素数量。
  • 地理空间(Geospatial):用于存储地理位置信息。
  • 发布/订阅(Pub/Sub):一种消息通信模式,允许客户端订阅消息通道,并接收发布到该通道的消息。
  • 流(Streams):用于消息队列和日志存储,支持消息的持久化和时间排序。
  • 模块(Modules):Redis 支持动态加载模块,可以扩展 Redis 的功能。

String(字符串)

string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据,比如jpg图片或者序列化的对象。string 类型是 Redis 最基本的数据类型,string 类型的值最大能存储 512MB。

keyvalue
name“zhangsan”
ege“15”

常用命令:

  • SET key value:设置键的值,重复设置会覆盖原来的值。
  • GET key:获取键的值。
  • INCR key:将键的值加 1。
  • DECR key:将键的值减 1。
  • APPEND key value:将值追加到键的值之后。

Hash(哈希)

hash 类型是一个键值对集合,是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。比如存储用户的 id、姓名、年龄、性别等信息。文章的 id、标题、内容、作者等信息等。每个哈希最多可以存储 2^32 - 1 个键值对。

keyfieldvalue
user1name“zhangsan”
ege“15”

常用命令:

  • HSET key field value:设置哈希表中字段的值。
  • HGET key field:获取哈希表中字段的值。
  • HGETALL key:获取哈希表中所有字段和值。
  • HDEL key field:删除哈希表中的字段。

List(列表)

list 类型是一个有序的字符串集合,每个元素都有一个索引。Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。列表最多可以存储 2^32 - 1 个元素。

keyvalue
name“zhangsan”
“lisi”

常用命令:

  • LPUSH key value:将值插入到列表的头部。
  • RPUSH key value:将值插入到列表的尾部。
  • LPOP key:移除并返回列表的头部元素。
  • RPOP key:移除并返回列表的尾部元素。
  • LRANGE key start stop:返回列表中指定范围内的元素。

Set(无序集合)

set 类型是一个无序的字符串集合,每个元素都是唯一的。

keymember
name“zhangsan”
“lisi”

常用命令:

  • SADD key member:将成员添加到集合中。
  • SREM key member:将成员从集合中移除。
  • SISMEMBER key member:判断成员是否在集合中。
  • SMEMBERS key:返回集合中的所有成员。

ZSet(有序集合)

zset 类型是一个有序的字符串集合,每个元素都有一个分数(score)与之关联。

keymemberscore
name“zhangsan”1
“lisi”2

常用命令:

  • ZADD key score member:将成员添加到有序集合中,并关联一个分数。
  • ZREM key member:将成员从有序集合中移除。
  • ZSCORE key member:获取成员的分数。
  • ZRANGE key start stop:返回有序集合中指定范围内的元素。

1. 继承Redis

1
2
3
4
5
6
7
8
9
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--redis序列化和反序列化-->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
</dependency>

2. 配置文件

1
2
3
4
5
6
spring:
  redis:
    host: localhost
    port: 6379
    database: 0
    password: 

3. 配置RedisTemplate

为了更方便地操作 Redis,你可以配置 RedisTemplate,并设置合适的序列化器。

创建配置文件:RedisConfig

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.example.demo.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        // 设置键的序列化器
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);

        // 设置值的序列化器,可以直接将Object保存到RedisString中,并从RedisString中查询后返回Object
        GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer(new ObjectMapper());
        redisTemplate.setValueSerializer(jsonRedisSerializer);
        redisTemplate.setHashValueSerializer(jsonRedisSerializer);

        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

4. 使用RedisTemplate操作Redis

现在你可以在你的服务中注入 RedisTemplate,并使用它来操作 Redis。

RedisStringService.java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package com.example.demo.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class RedisStringService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate; // 值的类型可以是String,也可以是Object类型,因为我们已经配置了GenericJackson2JsonRedisSerializer作为序列化器。这样你就可以存储任何Java对象到Redis中,并且能够自动进行JSON的

    /**
     * 存储String值到Redis
     * @param key 键
     * @param object 值(可以是对象,redisTemplate自动序列化存储和反序列化返回)
     */
    public void setStringValue(String key, Object object) {
        redisTemplate.opsForValue().set(key, object);
    }
    /**
     * 设置String类型值,支持设置过期时间
     *
     * @param key     键
     * @param object   值
     * @param timeout 过期时间,如果小于等于0,则不设置过期时间
     * @param unit 时间单位,如果为null,默认为秒
     */
    public void setStringValue(String key, Object object, long timeout, TimeUnit unit) {
        // 当过期时间小于等于0时,不设置过期时间
        if (timeout <= 0) {
            redisTemplate.opsForValue().set(key, object);
        }
        // 如果时间单位为null,默认设置为秒
        if (unit == null) {
            unit = TimeUnit.SECONDS;
        }
        // 设置键值对,并指定过期时间
        redisTemplate.opsForValue().set(key, object, timeout, unit);
    }
    /**
     * 根据键获取字符串值
     *
     * @param key 键,用于标识存储在Redis中的值
     * @return 与键关联的字符串值,如果键不存在则返回null
     */
    public Object getStringValue(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    /**
     * 删除指定的字符串值
     * 通过调用RedisTemplate的delete方法来删除给定键对应的字符串值
     * 主要用于在Redis中移除不再需要的字符串类型数据
     *
     * @param key Redis中的键,用于定位要删除的字符串值
     */
    public void deleteStringValue(String key) {
        redisTemplate.delete(key);
    }

}

也可以配置多种类型

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Set;
import java.util.concurrent.TimeUnit;

@Service
public class RedisService {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    // String类型
    public void setStringValue(String key, String value, long timeout, TimeUnit timeUnit) {
        if (timeout <= 0) {
            redisTemplate.opsForValue().set(key, value);
        }
        if (timeUnit == null) {
            timeUnit = TimeUnit.SECONDS;
        }
        redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
    }
    public String getStringValue(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    // Hash类型
    public void setHashValue(String key, String hashKey, String value) {
        redisTemplate.opsForHash().put(key, hashKey, value);
    }
    public String getHashValue(String key, String hashKey) {
        return (String) redisTemplate.opsForHash().get(key, hashKey);
    }

    // List类型
    public void addToList(String key, String value) {
        redisTemplate.opsForList().rightPush(key, value);
    }
    public String getFromList(String key, long index) {
        return (String) redisTemplate.opsForList().index(key, index);
    }

    // Set类型
    public void addToSet(String key, String value) {
        redisTemplate.opsForSet().add(key, value);
    }
    public Set<String> getFromSet(String key) {
        return redisTemplate.opsForSet().members(key);
    }

    // ZSet类型(有序)
    public void addToZSet(String key, String value, double score) {
        redisTemplate.opsForZSet().add(key, value, score);
    }
    public Set<String> getRangeFromZSet(String key, long start, long end) {
        return redisTemplate.opsForZSet().range(key, start, end);
    }
}

RedisHashService.java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package com.example.demo.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Map;

@Service
public class RedisHashService {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 向Hash中添加一个字段和值
     * @param hashKey  Hash的键
     * @param field    字段名
     * @param value    字段值
     */
    public void putHashValue(String hashKey, String field, String value) {
        HashOperations<String, String, String> hashOps = redisTemplate.opsForHash();
        hashOps.put(hashKey, field, value);
    }
    /**
     * 从Hash中获取一个字段的值
     * @param hashKey  Hash的键
     * @param field    字段名
     * @return         字段值
     */
    public String getHashValue(String hashKey, String field) {
        HashOperations<String, String, String> hashOps = redisTemplate.opsForHash();
        return hashOps.get(hashKey, field);
    }

    /**
     * 向Hash中添加多个字段和值
     * @param hashKey  Hash的键
     * @param map      包含多个字段和值的Map
     */
    public void putAllHashValues(String hashKey, Map<String, String> map) {
        HashOperations<String, String, String> hashOps = redisTemplate.opsForHash();
        hashOps.putAll(hashKey, map);
    }
    /**
     * 获取Hash中的所有字段和值
     * @param hashKey  Hash的键
     * @return         包含所有字段和值的Map
     */
    public Map<String, String> getAllHashValues(String hashKey) {
        HashOperations<String, String, String> hashOps = redisTemplate.opsForHash();
        return hashOps.entries(hashKey);
    }

    /**
     * 删除Hash中的一个或多个字段
     * @param hashKey  Hash的键
     * @param fields   要删除的字段名数组
     */
    public void deleteHashFields(String hashKey, String... fields) {
        HashOperations<String, String, String> hashOps = redisTemplate.opsForHash();
        hashOps.delete(hashKey, (Object[]) fields);
    }

}

RedisListService.java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package com.example.demo.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class RedisListService {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 从列表左侧插入一个值
     * @param key 列表的键
     * @param value 要插入的值
     * @return 插入后列表的长度
     */
    public Long leftPush(String key, String value) {
        ListOperations<String, String> listOps = redisTemplate.opsForList();
        return listOps.leftPush(key, value);
    }

    /**
     * 从列表右侧插入一个值
     * @param key 列表的键
     * @param value 要插入的值
     * @return 插入后列表的长度
     */
    public Long rightPush(String key, String value) {
        ListOperations<String, String> listOps = redisTemplate.opsForList();
        return listOps.rightPush(key, value);
    }

    /**
     * 从列表左侧移除并返回一个值
     * @param key 列表的键
     * @return 移除的值
     */
    public String leftPop(String key) {
        ListOperations<String, String> listOps = redisTemplate.opsForList();
        return listOps.leftPop(key);
    }

    /**
     * 从列表右侧移除并返回一个值
     * @param key 列表的键
     * @return 移除的值
     */
    public String rightPop(String key) {
        ListOperations<String, String> listOps = redisTemplate.opsForList();
        return listOps.rightPop(key);
    }

    /**
     * 获取列表指定范围内的元素
     * @param key 列表的键
     * @param start 起始索引
     * @param end 结束索引
     * @return 指定范围内的元素列表
     */
    public List<String> range(String key, long start, long end) {
        ListOperations<String, String> listOps = redisTemplate.opsForList();
        return listOps.range(key, start, end);
    }

    /**
     * 获取列表的长度
     * @param key 列表的键
     * @return 列表的长度
     */
    public Long size(String key) {
        ListOperations<String, String> listOps = redisTemplate.opsForList();
        return listOps.size(key);
    }

}

RedisSetService.java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package com.example.demo.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.stereotype.Service;

import java.util.Set;

@Service
public class RedisSetService {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 向Set中添加一个或多个元素
     * @param key  Set的键
     * @param values 要添加的元素
     * @return 添加成功的元素数量
     */
    public Long add(String key, String... values) {
        SetOperations<String, String> setOps = redisTemplate.opsForSet();
        return setOps.add(key, values);
    }

    /**
     * 获取Set中的所有元素
     * @param key  Set的键
     * @return Set中的所有元素
     */
    public Set<String> members(String key) {
        SetOperations<String, String> setOps = redisTemplate.opsForSet();
        return setOps.members(key);
    }

    /**
     * 检查元素是否存在于Set中
     * @param key  Set的键
     * @param value 要检查的元素
     * @return 如果元素存在返回true,否则返回false
     */
    public Boolean isMember(String key, String value) {
        SetOperations<String, String> setOps = redisTemplate.opsForSet();
        return setOps.isMember(key, value);
    }

    /**
     * 从Set中移除一个或多个元素
     * @param key  Set的键
     * @param values 要移除的元素
     * @return 移除成功的元素数量
     */
    public Long remove(String key, String... values) {
        SetOperations<String, String> setOps = redisTemplate.opsForSet();
        return setOps.remove(key, (Object[]) values);
    }

    /**
     * 获取Set的元素数量
     * @param key  Set的键
     * @return Set的元素数量
     */
    public Long size(String key) {
        SetOperations<String, String> setOps = redisTemplate.opsForSet();
        return setOps.size(key);
    }

}

RedisZSetService.java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
package com.example.demo.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.util.Set;

@Service
public class RedisZSetService {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 向ZSet中添加一个元素及其分数
     * @param key  ZSet的键
     * @param value 要添加的元素
     * @param score 元素的分数
     * @return 如果元素是新添加的返回true,否则返回false
     */
    public Boolean add(String key, String value, double score) {
        ZSetOperations<String, String> zSetOps = redisTemplate.opsForZSet();
        return zSetOps.add(key, value, score);
    }

    /**
     * 获取ZSet中指定排名范围内的元素
     * @param key  ZSet的键
     * @param start 起始排名
     * @param end 结束排名
     * @return 指定排名范围内的元素
     */
    public Set<String> range(String key, long start, long end) {
        ZSetOperations<String, String> zSetOps = redisTemplate.opsForZSet();
        return zSetOps.range(key, start, end);
    }

    /**
     * 获取ZSet中指定分数范围内的元素
     * @param key  ZSet的键
     * @param min 最小分数
     * @param max 最大分数
     * @return 指定分数范围内的元素
     */
    public Set<String> rangeByScore(String key, double min, double max) {
        ZSetOperations<String, String> zSetOps = redisTemplate.opsForZSet();
        return zSetOps.rangeByScore(key, min, max);
    }

    /**
     * 从ZSet中移除一个或多个元素
     * @param key  ZSet的键
     * @param values 要移除的元素
     * @return 移除成功的元素数量
     */
    public Long remove(String key, String... values) {
        ZSetOperations<String, String> zSetOps = redisTemplate.opsForZSet();
        return zSetOps.remove(key, (Object[]) values);
    }

    /**
     * 获取ZSet的元素数量
     * @param key  ZSet的键
     * @return ZSet的元素数量
     */
    public Long zCard(String key) {
        ZSetOperations<String, String> zSetOps = redisTemplate.opsForZSet();
        return zSetOps.zCard(key);
    }

}

5.使用Redis

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/redis")
public class RedisController {

    @Autowired
    private RedisStringService redisStringService;

    @PostMapping("/set")
    public String setValue(@RequestParam String key, @RequestParam String value) {
        redisStringService.setValue(key, value);
        return "Value set successfully";
    }

    @GetMapping("/get")
    public Object getValue(@RequestParam String key) {
        return redisStringService.getValue(key);
    }

    @DeleteMapping("/delete")
    public String deleteValue(@RequestParam String key) {
        boolean result = redisStringService.deleteValue(key);
        if (result) {
            return "Value deleted successfully";
        } else {
            return "Failed to delete value";
        }
    }
}

6. 运行并测试

启动 Spring Boot 项目,你可以使用工具(如 Postman)来测试 Redis 操作:

  • 存储数据:发送 POST 请求到 http://localhost:8080/redis/set?key=testKey&value=testValue。
  • 获取数据:发送 GET 请求到 http://localhost:8080/redis/get?key=testKey。
  • 删除数据:发送 DELETE 请求到 http://localhost:8080/redis/delete?key=testKey。

7、应用场景

  • 场景一:缓存数据,Redis 可以用作缓存层,存储经常访问的数据,以提高系统的性能和响应速度。
  • 场景二:分布式锁,Redis 提供了分布式锁的实现,可以用于在分布式系统中实现互斥访问。
  • 场景三:消息队列,Redis 提供了发布/订阅功能,可以用于构建消息队列系统。
  • 场景四:计数器,Redis 提供了原子操作,可以用于实现计数器功能。

8、注意事项

  • 注意数据一致性,Redis 是一个内存数据库,数据可能会丢失,如果需要保证数据的一致性,需要使用其他的持久化方式。
  • 注意数据的过期时间,Redis 提供了过期时间的设置,可以用于控制数据的生命周期。
  • 注意数据的序列化方式,Redis 支持多种序列化方式,可以根据实际需求选择合适的序列化方式。

9、特殊场景分析

多维对象数据

比如用户信息,包含用户 ID、用户名、密码、邮箱等信息,还有地址信息,包含省份、城市、街道等信息,还有订单信息,包含订单 ID、订单金额、订单状态等信息。

  • 使用 Redis 的 Hash 类型存储多维对象数据,将二级信息按照address.city格式存储。适用于对象属性较少且访问频率较高的情况,方便对单个属性进行读写操作。
  • 使用 JSON 序列化存储为 String,使用 Jackson 序列化工具。适用于对象结构复杂、嵌套层级深的情况,简单易用,但读写时需要进行序列化和反序列化操作,可能会影响性能。
  • 结合使用多种数据结构:适用于对象不同部分有不同的访问模式和操作需求的情况,可以根据实际情况灵活选择数据结构。

Redis基础教程:https://www.runoob.com/redis/redis-tutorial.html