不能靠改spring.redis.database动态切换,因该配置仅启动时生效;必须为每个数据源定义独立的RedisConnectionFactory+RedisTemplate,并用ThreadLocal实现运行时路由。

不能靠改 spring.redis.database 配置项动态切换,它只在启动时生效;真正可行的是为每个数据源定义独立的 RedisConnectionFactory + RedisTemplate,再用 ThreadLocal 做运行时路由。
为什么不能直接调用 select() 切库
很多人试过在代码里写 jedis.getConnection().select(1) 或类似操作,结果发现:要么抛 RedisConnectionException,要么切换后其他线程也跟着变,根本不可控。这是因为 RedisTemplate 底层连接是池化的,select() 只影响当前连接实例,而连接可能被归还到池中、被其他请求复用,导致行为不可预测。
-
JedisConnectionFactory初始化时就绑定了database参数,之后无法修改 - 手动调用
select()属于破坏连接池契约的操作,Spring Data Redis 不支持 - 即使临时生效,也无法保证事务、Pipeline、回调等场景下的语义一致性
必须为每个数据源配一套独立的工厂和模板
Spring Boot 的自动配置只生成一份默认 RedisConnectionFactory 和 RedisTemplate,多数据源必须手动声明 Bean。关键不是“多配几个”,而是隔离粒度要到连接工厂级别。
- 每个数据源对应一个
@Configuration类,内含RedisConnectionFactory+RedisTemplate+StringRedisTemplate三件套 - 工厂必须用
@Primary标出默认项,避免@Autowired注入冲突 - 模板的序列化器要显式指定,比如
StringRedisSerializer对 key,GenericJackson2JsonRedisSerializer对 value,否则跨模板存取容易乱码 - 配置类要用
@ConfigurationProperties绑定不同前缀,例如spring.data.redis.auth和spring.data.redis.chat
用 AbstractRoutingDataSource 思路迁移到 Redis
虽然 Spring 没提供现成的 AbstractRoutingRedisConnectionFactory,但你可以仿照 dynamic-datasource 的思路手写一个路由工厂。核心是重写 determineCurrentLookupKey(),从 ThreadLocal 读取当前目标库名或标识。
- 定义一个
DynamicRedisConnectionFactory extends RedisConnectionFactory,内部维护Map - 每次
getConnection()调用前,先通过DynamicRedisContextHolder.peek()获取 key,再查 Map 拿对应工厂 - 切库动作收口到工具类,比如
DynamicRedisUtil.use("auth"),它往ThreadLocal写值并注册reset()清理钩子 - 务必在
@Async或新线程中手动传递上下文,ThreadLocal不会自动继承
最容易被忽略的坑:连接池与监控埋点
多个 RedisConnectionFactory 共享同一套连接池参数(如 max-active)时,实际总连接数会翻倍,可能打爆 Redis 服务器。同时,各模板的 RedisTemplate 默认不带监控指标,线上出问题时无法区分是哪个数据源拖慢了整体。
- 每个工厂的连接池配置必须独立命名,比如
auth.jedis.pool.max-active、chat.jedis.pool.max-active - 启用
LettuceClientConfigurationBuilderCustomizer为每个工厂注入不同ClientResources,便于打点 - 不要在
@PostConstruct里调用任意RedisTemplate方法——此时连接工厂可能还没初始化完,会触发循环依赖 - 如果用了 Redisson,注意它不兼容这套路由逻辑,得单独封装











