Skip to content

Latest commit

History

13 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

简单实现 Spring Boot 多数据源

Simple Spring Boot Multi-DataSource

Usage

// In Mapper@UsingDataSource(DataSourceType.SLAVE)
UserselectByPrimaryKey(Integerid);
// Or In Service@UsingDataSource(DataSourceType.MASTER)
publicUsergetUserFromSlave1(Integerid) {
returnuserDao.selectByPrimaryKey(id);
}
@UsingDataSource(DataSourceType.SLAVE)
publicUsergetUserFromSlave(Integerid) {
returnuserDao.selectByPrimaryKey(id);
}

How to

  1. 在 application.yml 中添加数据源对应的配置信息

    spring:
    datasource:
    master:
    jdbc-url: jdbc:mysql://localhost:3306/multi_datasource_masterusername: rootpassword: rootrootslave:
    jdbc-url: jdbc:mysql://localhost:3306/multi_datasource_slaveusername: rootpassword: rootrootslave2:
    jdbc-url: jdbc:mysql://localhost:3306/multi_datasource_slave_2username: rootpassword: rootroot
  2. 数据源配置

    @Configuration@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
    publicclassDataSourceConfig {
    /** * 主库数据源配置,Bean name 与 {@link DataSourceType} 中对应枚举类型名相同,以达到校验作用 */@Bean("MASTER")
    @ConfigurationProperties(prefix = "spring.datasource.master")
    publicDataSourcemasterDataSource() {
    returnDataSourceBuilder.create().build();
    }
    /** * 从库 1 数据源配置 */@Bean("SLAVE")
    @ConfigurationProperties(prefix = "spring.datasource.slave")
    publicDataSourceslaveDataSource() {
    returnDataSourceBuilder.create().build();
    }
    /** * 从库 2 数据源配置 */@Bean("SLAVE_2")
    @ConfigurationProperties(prefix = "spring.datasource.slave2")
    publicDataSourceslave2DataSource() {
    returnDataSourceBuilder.create().build();
    }
    }
  3. 定义数据源类型枚举

    publicenumDataSourceType {
    /** * 主库 */MASTER,
    /** * 从库 1 */SLAVE,
    /** * 从库 2 */SLAVE_2,
    ;
    /** * 默认的数据源类型 */publicstaticfinalDataSourceTypeDEFAULT = MASTER;
    }
  4. 动态数据源配置,配合 UsingDataSource、UsingDataSourceAspect 实现数据源切换

    @Primary@ComponentpublicclassDynamicRoutingDataSourceextendsAbstractRoutingDataSource {
    privatefinalMap<String, DataSource> dataSourceMap;
    publicstaticfinalThreadLocal<DataSourceType> TYPE_HOLDER = ThreadLocal.withInitial(() -> DataSourceType.DEFAULT);
    publicDynamicRoutingDataSource(Map<String, DataSource> dataSourceMap) {
    this.dataSourceMap = dataSourceMap;
    }
    @OverrideprotectedObjectdetermineCurrentLookupKey() {
    returnTYPE_HOLDER.get();
    }
    @PostConstructprivatevoidpostConstruct() {
    // 设置默认数据源StringdefaultDataSourceName = DataSourceType.DEFAULT.name();
    DataSourcedefaultDataSource = dataSourceMap.get(defaultDataSourceName);
    setDefaultTargetDataSource(defaultDataSource);
    // 设置数据源及其类型映射Map<Object, Object> targetDataSources = newHashMap<>();
    dataSourceMap.forEach((name, ds) -> targetDataSources.put(DataSourceType.valueOf(name), ds));
    setTargetDataSources(targetDataSources);
    }
    }
  5. 指定使用数据源类型注解

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface UsingDataSource {
    DataSourceTypevalue() defaultDataSourceType.MASTER;
    }
  6. 数据源切换拦截切面

    @Slf4j@Aspect@ComponentpublicclassUsingDataSourceAspect {
    @Around("@annotation(usingDataSource)")
    publicObjectaround(ProceedingJoinPointjoinPoint, UsingDataSourceusingDataSource) throwsThrowable {
    DataSourceTypetype = usingDataSource.value();
    log.debug("data source type is {}", type);
    // 保存要切换到的数据源类型DynamicRoutingDataSource.TYPE_HOLDER.set(type);
    Objectres;
    try {
    res = joinPoint.proceed();
    } finally {
    // 恢复数据源DynamicRoutingDataSource.TYPE_HOLDER.remove();
    }
    returnres;
    }
    }
  7. 使用

    @ServicepublicclassUserService {
    privatefinalUserDaouserDao;
    publicUserService(UserDaouserDao) {
    this.userDao = userDao;
    }
    publicUsergetUser(Integerid) {
    returnuserDao.selectByPrimaryKey(id);
    }
    @UsingDataSourcepublicUsergetUserFromDefault(Integerid) {
    returnuserDao.selectByPrimaryKey(id);
    }
    @UsingDataSource(DataSourceType.SLAVE)
    publicUsergetUserFromSlave1(Integerid) {
    returnuserDao.selectByPrimaryKey(id);
    }
    @UsingDataSource(DataSourceType.SLAVE_2)
    publicUsergetUserFromSlave2(Integerid) {
    returnuserDao.selectByPrimaryKey(id);
    }
    }
  8. Have fun! 😁

    你可以使用 MultiDatasourceApplicationTests.getUser() 进行测试

    @SpringBootTestclassMultiDatasourceApplicationTests {
    @AutowiredprivateUserServiceuserService;
    @TestvoidcontextLoads() {
    }
    @TestpublicvoidgetUser() {
    Useruser;
    user = userService.getUser(1);
    System.out.println("user = " + user);
    user = userService.getUserFromDefault(1);
    System.out.println("user = " + user);
    user = userService.getUserFromSlave1(1);
    System.out.println("user = " + user);
    user = userService.getUserFromSlave2(1);
    System.out.println("user = " + user);
    user = userService.getUser(1);
    System.out.println("user = " + user);
    user = userService.getUserFromDefault(1);
    System.out.println("user = " + user);
    user = userService.getUserFromSlave1(1);
    System.out.println("user = " + user);
    user = userService.getUserFromSlave2(1);
    System.out.println("user = " + user);
    }
    }
    user = User(id=1, username=master_username, password=master_password, sex=1, create_time=Fri Feb 19 11:59:35 CST 2021, update_time=Fri Feb 19 11:59:35 CST 2021, deleted=0)
    2021-02-20 10:02:12.169 INFO 13053 --- [ main] c.e.m.config.UsingDataSourceAspect : data sourcetype is MASTER
    user = User(id=1, username=master_username, password=master_password, sex=1, create_time=Fri Feb 19 11:59:35 CST 2021, update_time=Fri Feb 19 11:59:35 CST 2021, deleted=0)
    2021-02-20 10:02:12.171 INFO 13053 --- [ main] c.e.m.config.UsingDataSourceAspect : data sourcetype is SLAVE
    user = User(id=1, username=slave_username, password=slave_password, sex=1, create_time=Fri Feb 19 17:05:37 CST 2021, update_time=Fri Feb 19 17:05:37 CST 2021, deleted=0)
    2021-02-20 10:02:12.186 INFO 13053 --- [ main] c.e.m.config.UsingDataSourceAspect : data sourcetype is SLAVE_2
    user = User(id=1, username=slave_2_username, password=slave_2_password, sex=1, create_time=Sat Feb 20 10:00:59 CST 2021, update_time=Sat Feb 20 10:00:59 CST 2021, deleted=0)
    user = User(id=1, username=master_username, password=master_password, sex=1, create_time=Fri Feb 19 11:59:35 CST 2021, update_time=Fri Feb 19 11:59:35 CST 2021, deleted=0)
    2021-02-20 10:02:12.203 INFO 13053 --- [ main] c.e.m.config.UsingDataSourceAspect : data sourcetype is MASTER
    user = User(id=1, username=master_username, password=master_password, sex=1, create_time=Fri Feb 19 11:59:35 CST 2021, update_time=Fri Feb 19 11:59:35 CST 2021, deleted=0)
    2021-02-20 10:02:12.206 INFO 13053 --- [ main] c.e.m.config.UsingDataSourceAspect : data sourcetype is SLAVE
    user = User(id=1, username=slave_username, password=slave_password, sex=1, create_time=Fri Feb 19 17:05:37 CST 2021, update_time=Fri Feb 19 17:05:37 CST 2021, deleted=0)
    2021-02-20 10:02:12.208 INFO 13053 --- [ main] c.e.m.config.UsingDataSourceAspect : data sourcetype is SLAVE_2
    user = User(id=1, username=slave_2_username, password=slave_2_password, sex=1, create_time=Sat Feb 20 10:00:59 CST 2021, update_time=Sat Feb 20 10:00:59 CST 2021, deleted=0)

About

🚥 Simple Spring Boot Multi DataSource(100 行代码手把手教你实现 Spring Boot 多数据源)

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages