如何在Spring中为多个数据源设置liquibase?

时间:2017-04-20 15:33:23

标签: spring spring-boot spring-data liquibase

我需要为liquibase中的两个datasources设置Spring,此时似乎只有一个liquibase设置可用,您可以选择数据来源。

5 个答案:

答案 0 :(得分:17)

如果您使用的是弹簧靴,可以使用以下设置:

配置类:

@Configuration
public class DatasourceConfig {

    @Primary
    @Bean
    @ConfigurationProperties(prefix = "datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "datasource.primary.liquibase")
    public LiquibaseProperties primaryLiquibaseProperties() {
        return new LiquibaseProperties();
    }

    @Bean
    public SpringLiquibase primaryLiquibase() {
        return springLiquibase(primaryDataSource(), primaryLiquibaseProperties());
    }

    @Bean
    @ConfigurationProperties(prefix = "datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "datasource.secondary.liquibase")
    public LiquibaseProperties secondaryLiquibaseProperties() {
        return new LiquibaseProperties();
    }

    @Bean
    public SpringLiquibase secondaryLiquibase() {
        return springLiquibase(secondaryDataSource(), secondaryLiquibaseProperties());
    }

    private static SpringLiquibase springLiquibase(DataSource dataSource, LiquibaseProperties properties) {
        SpringLiquibase liquibase = new SpringLiquibase();
        liquibase.setDataSource(dataSource);
        liquibase.setChangeLog(properties.getChangeLog());
        liquibase.setContexts(properties.getContexts());
        liquibase.setDefaultSchema(properties.getDefaultSchema());
        liquibase.setDropFirst(properties.isDropFirst());
        liquibase.setShouldRun(properties.isEnabled());
        liquibase.setLabels(properties.getLabels());
        liquibase.setChangeLogParameters(properties.getParameters());
        liquibase.setRollbackFile(properties.getRollbackFile());
        return liquibase;
    }


...

}

properties.yml

datasource:
  primary:
    url: jdbc:mysql://localhost/primary
    username: username
    password: password
    liquibase:
      change-log: classpath:/db/changelog/db.primary.changelog-master.xml
  secondary:
    url: jdbc:mysql://localhost/secondary
    username: username
    password: password
    liquibase:
      change-log: classpath:/db/changelog/db.secondary.changelog-master.xml

答案 1 :(得分:1)

我需要支持动态数量的DataSource,而不是固定数量的DataSource。我发现您可以通过提供如下服务来为多个数据源使用相同的SpringLiquibase bean:

@Service
@DependsOn("liquibase")
public class LiquibaseService {

    @Autowired
    @Qualifier("liquibase")
    private SpringLiquibase liquibase;

    @PostConstruct
    public void initialize() {

        /* Obtain datasources from wherever. I obtain them from a master DB. It's up to you. */
        List<DataSource> dataSources = obtainDataSources();

        for (DataSource dataSource : dataSources) {
            try {
                liquibase.setDataSource(dataSource);
                liquibase.setChangeLog("classpath:liquibase/emp.changelog.xml");
                liquibase.setShouldRun(true);

                // This runs Liquibase
                liquibase.afterPropertiesSet();

            } catch (LiquibaseException ex) {
                throw new RuntimeException(ex);
            }
        }
    }

}

为此,您应该在某个地方声明一个SpringLiquibase bean。在此示例中,我将其保存在一个配置文件中:

@Bean
public SpringLiquibase liquibase(LiquibaseProperties properties) {

    SpringLiquibase liquibase = new SpringLiquibase();
    liquibase.setDataSource(systemDataSource);
    liquibase.setChangeLog("classpath:liquibase/sis.changelog.xml");
    liquibase.setContexts(properties.getContexts());
    liquibase.setDefaultSchema(properties.getDefaultSchema());
    liquibase.setDropFirst(properties.isDropFirst());


    liquibase.setLabels(properties.getLabels());
    liquibase.setChangeLogParameters(properties.getParameters());
    liquibase.setRollbackFile(properties.getRollbackFile());

    // This is because we are running the process manually. Don't let SpringLiquibase do it.
    liquibase.setShouldRun(false);

    return liquibase;
}

以上内容很大程度上取决于您的DataSource配置要求。您可能还需要将其放在主Application类上,这样Spring-Liquibase的自动配置就不会起作用:

@SpringBootApplication(exclude = {
    LiquibaseAutoConfiguration.class
})
public class Application {

    // Stuff...

}

答案 2 :(得分:0)

只有2个数据源和2个豆

<bean id="liquibase1" class="liquibase.integration.spring.SpringLiquibase">
      <property name="dataSource" ref="dataSource1" />
      <property name="changeLog" value="classpath:db1-changelog.xml" />
 </bean>
 <bean id="liquibase2" class="liquibase.integration.spring.SpringLiquibase">
      <property name="dataSource" ref="dataSource2" />
      <property name="changeLog" value="classpath:db2-changelog.xml" />
 </bean>

答案 3 :(得分:0)

您还可以运行多个liquibase实例(即不仅限于主要和次要)。

e.g。您的配置java可以包含:

@Bean
@ConfigurationProperties(prefix = "liquibase1")
...
@Bean
@ConfigurationProperties(prefix = "liquibase2")
...
@Bean
@ConfigurationProperties(prefix = "liquibase3")

您的application.property可以:

liquibase1.default-schema=schemaA
...
liquibase2.default-schema=schemaB
...
liquibase3.default-schema=schemaC
...

而且(令人兴奋的是),这些springLiquibase实例可以使用相同的Datasource或不同的DataSource ......但是你喜欢它。

运行顺序?我没有找到任何官方文档,根据我在调试中的观察,所有liquibase迁移都按照你在application.properties中编写的顺序运行。那些想要在一个数据源中运行迁移,然后转到另一个数据源,然后回到这个数据源并运行其他东西的人,你可能想尝试这种多个liquibase实例方法。

答案 4 :(得分:0)

我已经完成了一个项目,可以使用您的特定changeSets创建多个dataSources,因此,如果您需要添加另一个dataSource,则只需更改application.yml,而无需更改代码。

配置类

@Configuration
@ConditionalOnProperty(prefix = "spring.liquibase", name = "enabled", matchIfMissing = true)
@EnableConfigurationProperties(LiquibaseProperties.class)
@AllArgsConstructor
public class LiquibaseConfiguration {

    private LiquibaseProperties properties;
    private DataSourceProperties dataSourceProperties;

    @Bean
    @DependsOn("tenantRoutingDataSource")
    public MultiTenantDataSourceSpringLiquibase liquibaseMultiTenancy(Map<Object, Object> dataSources,
                                                                      @Qualifier("taskExecutor") TaskExecutor taskExecutor) {
        // to run changeSets of the liquibase asynchronous
        MultiTenantDataSourceSpringLiquibase liquibase = new MultiTenantDataSourceSpringLiquibase(taskExecutor);
        dataSources.forEach((tenant, dataSource) -> liquibase.addDataSource((String) tenant, (DataSource) dataSource));
        dataSourceProperties.getDataSources().forEach(dbProperty -> {
            if (dbProperty.getLiquibase() != null) {
                liquibase.addLiquibaseProperties(dbProperty.getTenantId(), dbProperty.getLiquibase());
            }
        });

        liquibase.setContexts(properties.getContexts());
        liquibase.setChangeLog(properties.getChangeLog());
        liquibase.setDefaultSchema(properties.getDefaultSchema());
        liquibase.setDropFirst(properties.isDropFirst());
        liquibase.setShouldRun(properties.isEnabled());
        return liquibase;
    }

}

application.yml

spring:
  dataSources:
    - tenantId: db1
      url: jdbc:postgresql://localhost:5432/db1
      username: postgres
      password: 123456
      driver-class-name: org.postgresql.Driver
      liquibase:
        enabled: true
        default-schema: public
        change-log: classpath:db/master/changelog/db.changelog-master.yaml
    - tenantId: db2
      url: jdbc:postgresql://localhost:5432/db2
      username: postgres
      password: 123456
      driver-class-name: org.postgresql.Driver
    - tenantId: db3
      url: jdbc:postgresql://localhost:5432/db3
      username: postgres
      password: 123456
      driver-class-name: org.postgresql.Driver

存储库链接:https://github.com/dijalmasilva/spring-boot-multitenancy-datasource-liquibase