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。
key | value |
---|
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 个键值对。
key | field | value |
---|
user1 | name | “zhangsan” |
| ege | “15” |
常用命令:
- HSET key field value:设置哈希表中字段的值。
- HGET key field:获取哈希表中字段的值。
- HGETALL key:获取哈希表中所有字段和值。
- HDEL key field:删除哈希表中的字段。
List(列表)#
list 类型是一个有序的字符串集合,每个元素都有一个索引。Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。列表最多可以存储 2^32 - 1 个元素。
key | value |
---|
name | “zhangsan” |
| “lisi” |
常用命令:
- LPUSH key value:将值插入到列表的头部。
- RPUSH key value:将值插入到列表的尾部。
- LPOP key:移除并返回列表的头部元素。
- RPOP key:移除并返回列表的尾部元素。
- LRANGE key start stop:返回列表中指定范围内的元素。
Set(无序集合)#
set 类型是一个无序的字符串集合,每个元素都是唯一的。
key | member |
---|
name | “zhangsan” |
| “lisi” |
常用命令:
- SADD key member:将成员添加到集合中。
- SREM key member:将成员从集合中移除。
- SISMEMBER key member:判断成员是否在集合中。
- SMEMBERS key:返回集合中的所有成员。
ZSet(有序集合)#
zset 类型是一个有序的字符串集合,每个元素都有一个分数(score)与之关联。
key | member | score |
---|
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