MeteorCat / JPA-DataRedis多数据源切换

Created Sat, 28 Dec 2024 23:53:58 +0800 Modified Wed, 29 Oct 2025 23:25:00 +0800
874 Words

JPA-DataRedis多数据源切换

这里主要基于 SpringBoot 目前的 spring-boot-starter-data-redis Redis Repositories 依赖.

日常项目使用当中可能不止有单个 Redis, 有时候需要切换多个 Redis 方便读写数据, 这里目前网上数据比较少所以总结下.

首先就是引入目前组件依赖:

<!-- Redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

引入比较简单, 后续关键就是编写配置项, 这里就是相对比较复杂的阶段, 首先是定义 application.properties 内部配置:

# =====================================
# Redis中心库
# =====================================
spring.data.redis.center.host=192.168.1.110
spring.data.redis.center.port=6379
spring.data.redis.center.password=redis2024
spring.data.redis.center.database=0
# =====================================
# Redis会话库
# =====================================
spring.data.redis.session.host=192.168.1.100
spring.data.redis.session.port=6379
spring.data.redis.session.password=redis2024
spring.data.redis.session.database=1

这两个就是不同库对象和连接, 之后就是加载具体配置备用:


/**
 * 数据库多库配置, 这里编写集成数据库相关配置
 */
@Configuration
public class DataSourceConfig {

    /**
     * 注意:
     * 1.必须要利用 @Primary 指定默认数据库主库, 其他配置默认都为从库不需要配置该注解
     * 2.@Bean最好手动声明指定全局配置数据源名称,也就是指定 name 配置
     * 3.@ConfigurationProperties 就是获取到配置文件当中的 spring.data.redis.center 配置项
     * 4.@Qualifier 用来指定声明防止其他注册的 Bean 冲突
     */
    @Primary
    @Bean(name = "CenterDataSource")
    @Qualifier("CenterDataSource")
    @ConfigurationProperties(prefix = "spring.data.redis.center")
    public RedisProperties centerProperties() {
        return new RedisProperties();
    }


    /**
     * 注意:
     * 1.从库不需要 @Primary 指定默认数据库主库
     */
    @Bean(name = "SessionDataSource")
    @Qualifier("SessionDataSource")
    @ConfigurationProperties(prefix = "spring.data.redis.session")
    public RedisProperties sessionProperties() {
        return new RedisProperties();
    }
}

最后就是定义两个主要 Repositories 来启用连接和数据工厂配置:

// ------------------------------------------
// CenterDataSourceConfig 配置文件
// ------------------------------------------

/**
 * Redis配置
 * 1. redisTemplateRef 和 keyValueTemplateRef 必须同时配置才能生效
 * 2. EnableRedisRepositories.basePackages 用于扫描 repository 接口文件的路径
 * 3. EntityScan.basePackages 用于扫描 entity 实体文件的路径
 */
@Configuration
@EnableTransactionManagement
@EnableRedisRepositories(
        basePackages = {"com.meteorcat.devops.database.center.repository"},
        redisTemplateRef = "CenterRedisTemplateManager",
        keyValueTemplateRef = "CenterKeyValueTemplateManager"
)
@EntityScan(
        basePackages = {"com.meteorcat.devops.database.center.entity"})
public class CenterDataSourceConfig {

    final RedisProperties properties;

    public CenterDataSourceConfig(@Qualifier("CenterDataSource") RedisProperties properties) {
        this.properties = properties;
    }


    @Bean("CenterRedisConnectionFactory")
    public RedisConnectionFactory connectionFactory() {
        RedisStandaloneConfiguration conf = new RedisStandaloneConfiguration();
        conf.setHostName(properties.getHost());
        conf.setPort(properties.getPort());
        conf.setDatabase(properties.getDatabase());
        conf.setPassword(properties.getPassword());
        return new LettuceConnectionFactory(conf);
    }


    @Bean("CenterRedisTemplateManager")
    public RedisTemplate<?, ?> CenterRedisTemplateManager(@Qualifier("CenterRedisConnectionFactory") RedisConnectionFactory factory) {
        System.out.printf("CenterRedisTemplateManager,%d%n", properties.getDatabase());
        RedisTemplate<byte[], byte[]> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        template.afterPropertiesSet();
        return template;
    }


    @Bean("CenterKeyValueTemplateManager")
    public KeyValueTemplate CenterKeyValueTemplateManager(@Qualifier("CenterRedisTemplateManager") RedisTemplate<?, ?> template) {
        return new KeyValueTemplate(
                new RedisKeyValueAdapter(template),
                new RedisMappingContext()
        );
    }

}


// ============================================


/**
 * Redis配置
 */
@Configuration
@EnableTransactionManagement
@EnableRedisRepositories(
        basePackages = {"com.meteorcat.devops.database.session.repository"},
        redisTemplateRef = "SessionRedisTemplateManager",
        keyValueTemplateRef = "SessionKeyValueTemplateManager"
)
@EntityScan(
        basePackages = {"com.meteorcat.devops.database.session.entity"})
public class SessionDataSourceConfig {

    final RedisProperties properties;

    public SessionDataSourceConfig(@Qualifier("SessionDataSource") RedisProperties properties) {
        this.properties = properties;
    }

    @Bean("SessionRedisConnectionFactory")
    public RedisConnectionFactory connectionFactory() {
        RedisStandaloneConfiguration conf = new RedisStandaloneConfiguration();
        conf.setHostName(properties.getHost());
        conf.setPort(properties.getPort());
        conf.setDatabase(properties.getDatabase());
        conf.setPassword(properties.getPassword());
        return new LettuceConnectionFactory(conf);
    }


    @Bean("SessionRedisTemplateManager")
    public RedisTemplate<?, ?> SessionRedisTemplateManager(@Qualifier("SessionRedisConnectionFactory") RedisConnectionFactory factory) {
        System.out.printf("SessionRedisTemplateManager,%d%n", properties.getDatabase());
        RedisTemplate<byte[], byte[]> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        template.afterPropertiesSet();
        return template;
    }


    @Bean("SessionKeyValueTemplateManager")
    public KeyValueTemplate SessionKeyValueTemplateManager(@Qualifier("SessionRedisTemplateManager") RedisTemplate<?, ?> template) {
        return new KeyValueTemplate(
                new RedisKeyValueAdapter(template),
                new RedisMappingContext()
        );
    }

}

这里就定义两个数据源并且配置两者扫描目录分别是

  • com.meteorcat.devops.database.session
  • com.meteorcat.devops.database.center

只需要把对应实体文件放置于此就能切换不同数据源写入, 这里创建两个文件分别放置其中测试下是否会在两个不同 Redis 生成:

/**
 * 分别放入文件
 * com.meteorcat.devops.database.[session|center].entity.[CenterUser|SessionUser].java
 */
@Data
@RedisHash("mem_user")
public class CenterUser implements Serializable {


    @Id
    @Indexed
    private Long id;

    private String nickname;
}

// ============================================


/**
 * 同样放入 
 * com.meteorcat.devops.database.[session|center].repository.[ICenterUserRepository|ISessionUserRepository].java
 */
public interface ICenterUserRepository extends CrudRepository<CenterUser, Long> {
}

测试写入两者实体, 看看是否同步数据到不同数据库即可

注意: Jpa 的实体和数据工厂在项目当中不能存在同名, 这是必须要注意的.