Spring Boot 下使用 Redis,配置多个 database 数据源

兄弟们,上回咱唠了 Redis 默认 16 个库的门道,今儿咱接着整活儿 —— 在 Spring Boot 里咋配置多个 Redis database 数据源。是不是有兄弟在开发中遇到过这种情况:不同业务模块的数据想存到 Redis 的不同库里,比如用户模块用 0 号库,订单模块用 1 号库,可咋整?别慌,咱一步步来盘。

为啥要配置多个 Redis database 数据源?

先说说为啥咱需要在 Spring Boot 里搞多个 Redis database 数据源。举个栗子,假设咱搞个电商项目,用户信息、商品缓存、订单数据都得存 Redis。这时候要是全塞默认的 0 号库,键名一多就容易乱,而且后期维护起来也麻烦。要是能按业务分库存,比如用户数据放 1 号库,订单数据放 2 号库,那简直不要太爽,数据隔离性好,查起来也方便。

还有一种情况,就是咱可能得连不同的 Redis 实例,比如一个连主库,一个连从库,或者连不同环境的 Redis(测试环境、生产环境),这时候配置多个数据源就派上用场了。

Spring Boot 配置多个 Redis database 数据源的准备工作

咱先整个 Spring Boot 项目,引入 Redis 的依赖。一般来说,咱用 Spring Data Redis,在pom.xml里加上这玩意儿:

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

然后,咱得在application.yml或者application.properties里配置 Redis 的基本信息。如果是单实例 Redis,配置多个 database 数据源其实就是配置不同的database索引。要是连不同的 Redis 实例,还得配置不同的 IP、端口啥的。

单实例 Redis 配置多个 database 数据源

先整个简单的,单实例 Redis 配置多个 database 数据源,比如咱要配置两个数据源,一个连 0 号库,用于用户模块;一个连 1 号库,用于订单模块。

配置文件设置

application.yml里这么写:

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
spring:
redis:
host: 127.0.0.1
port: 6379
password: your_password # 要是没密码就不用写
timeout: 10s
# 主数据源,连0号库
database: 0
# 自定义连接池配置
lettuce:
pool:
min-idle: 0
max-idle: 8
max-active: 8
max-wait: -1ms

# 订单模块Redis配置,连1号库
redis:
order:
host: 127.0.0.1
port: 6379
password: your_password
timeout: 10s
database: 1
lettuce:
pool:
min-idle: 0
max-idle: 8
max-active: 8
max-wait: -1ms

配置类实现

接下来咱写配置类,创建两个RedisTemplate bean,分别对应不同的 database。

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 org.zxiat.speaker;

import com.alibaba.dubbo.common.utils.StringUtils;
import lombok.Value;

@Configuration
public class RedisConfig {
// 主数据源配置(0号库)
@Bean(name = "mainRedisTemplate")
public RedisTemplate<String, Object> mainRedisTemplate(
@Value("${spring.redis.host}") String host,
@Value("${spring.redis.port}") int port,
@Value("${spring.redis.password}") String password,
@Value("${spring.redis.database}") int database,
@Value("${spring.redis.timeout}") Duration timeout) {
return createRedisTemplate(host, port, password, database, timeout);
}

// 订单数据源配置(1号库)
@Bean(name = "orderRedisTemplate")
public RedisTemplate<String, Object> orderRedisTemplate(
@Value("${redis.order.host}") String host,

@Value("${redis.order.port}") int port,

@Value("${redis.order.password}") String password,

@Value("${redis.order.database}") int database,

@Value("${redis.order.timeout}") Duration timeout) {
return createRedisTemplate(host, port, password, database, timeout);
}


// 通用创建RedisTemplate方法
private RedisTemplate<String, Object> createRedisTemplate(String host, int port, String password, int database, Duration timeout) {
// 配置连接工厂
LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory();
lettuceConnectionFactory.setHostName(host);
lettuceConnectionFactory.setPort(port);

if (!StringUtils.isEmpty(password)) {
lettuceConnectionFactory.setPassword(password);
}

lettuceConnectionFactory.setDatabase(database);
lettuceConnectionFactory.setTimeout(timeout);
lettuceConnectionFactory.afterPropertiesSet();

// 创建RedisTemplate
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(lettuceConnectionFactory);

// 设置序列化方式,避免存到Redis的key和value乱码
StringRedisSerializer stringSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringSerializer);
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setHashKeySerializer(stringSerializer);
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.afterPropertiesSet();

return redisTemplate;
}
}

使用方式

配置好之后,咱在业务代码里就可以注入对应的RedisTemplate来使用了。比如用户模块用主数据源,订单模块用订单数据源:

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
package org.zxiat.speaker;

import com.alibaba.dubbo.config.annotation.Service;

@Service

public class UserService {
@Autowired
@Qualifier("mainRedisTemplate")
private RedisTemplate<String, Object> redisTemplate;

public void saveUser(String userId, User user) {
redisTemplate.opsForValue().set("user:" + userId, user);
}

public User getUser(String userId) {
return (User) redisTemplate.opsForValue().get("user:" + userId);
}
}


@Service

public class OrderService {
@Autowired
@Qualifier("orderRedisTemplate")
private RedisTemplate<String, Object> redisTemplate;

public void saveOrder(String orderId, Order order) {
redisTemplate.opsForValue().set("order:" + orderId, order);
}

public Order getOrder(String orderId) {
return (Order) redisTemplate.opsForValue().get("order:" + orderId);
}
}

连接不同 Redis 实例的多数据源配置

上面说的是单实例不同 database 的配置,要是咱得连不同的 Redis 实例,比如一个连生产环境的 Redis,一个连测试环境的 Redis,配置方式其实差不多,就是在配置文件里把不同实例的 IP、端口、database 都写上。

配置文件示例

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
spring:
redis:
# 生产环境Redis配置
prod:
host: 192.168.1.100
port: 6379
password: prod_password
database: 0
timeout: 10s
lettuce:
pool:
min-idle: 0
max-idle: 8
max-active: 8
max-wait: -1ms
# 测试环境Redis配置
test:
host: 192.168.1.101
port: 6379
password: test_password
database: 0
timeout: 10s
lettuce:
pool:
min-idle: 0
max-idle: 8
max-active: 8
max-wait: -1ms

配置类调整

配置类里创建不同的RedisTemplate,分别读取不同的配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Bean(name = "prodRedisTemplate")
public RedisTemplate<String, Object> prodRedisTemplate(
@Value("${spring.redis.prod.host}") String host,
@Value("${spring.redis.prod.port}") int port,
@Value("${spring.redis.prod.password}") String password,
@Value("${spring.redis.prod.database}") int database,
@Value("${spring.redis.prod.timeout}") Duration timeout) {
return createRedisTemplate(host, port, password, database, timeout);
}


@Bean(name = "testRedisTemplate")
public RedisTemplate<String, Object> testRedisTemplate(
@Value("${spring.redis.test.host}") String host,
@Value("${spring.redis.test.port}") int port,
@Value("${spring.redis.test.password}") String password,
@Value("${spring.redis.test.database}") int database,
@Value("${spring.redis.test.timeout}") Duration timeout) {
return createRedisTemplate(host, port, password, database, timeout);
}

集群模式下的多数据源配置

不过兄弟们得注意,要是用 Redis 集群(Cluster)模式,这时候 Redis 的 database 概念就被弱化了,因为集群是通过哈希槽(hash slot)来分片数据的,每个节点负责一部分槽位,这时候再按 database 分库就没啥意义了。

在集群模式下,咱要是想区分不同业务的数据,更推荐在键名里加前缀,比如user:1001order:2001,通过键名来区分不同业务的数据,这样更灵活,也符合集群的设计理念。

要是咱确实需要在集群模式下配置多个数据源,比如连不同的集群,配置方式和单实例类似,就是在配置文件里把不同集群的节点信息写上,然后创建不同的RedisConnectionFactoryRedisTemplate

总结

最后咱总结一下在 Spring Boot 里配置多个 Redis database 数据源的步骤和注意事项:

  1. 在配置文件里定义不同数据源的连接信息,包括 host、port、password、database 等;

  2. 创建配置类,为每个数据源创建对应的RedisTemplate bean,注意通过@Qualifier注解区分;

  3. 在业务代码里注入对应的RedisTemplate来使用;

  4. 如果是 Redis 集群模式,更推荐通过键名前缀来区分业务数据,而不是用 database;

  5. 配置时注意序列化方式,避免存到 Redis 的数据乱码。

怎么样,兄弟们,这下知道在 Spring Boot 里咋配置多个 Redis database 数据源了吧?实际开发中根据业务需求来整,该分库分库,该加前缀加前缀,把 Redis 玩得明明白白的。要是还有啥不明白的,评论区唠唠,咱一起琢磨琢磨。