具有 Spring 引导和多个模式的 Liquibase,如何指定执行顺序

Liquibase with Spring Boot and multiple schemas, how to specify execution order

我们有一个数据迁移作业需要按顺序初始化架构 AB。我们通过定义多个 SpringLiquibase 来处理多个模式,每个模式一个,每个都有自己的数据源和自己的主变更集。 (注意,通常在 Spring Boot 中您不需要定义 SpringLiquibase,因为它会检测单个数据源并使用该数据源为您自动配置 SpringLiquibase。 )

执行顺序似乎有所不同,具体取决于作业是 运行 在 IDE 本地,还是捆绑为单个 JAR Spring 启动应用程序。

如何保证liquibase的两次执行按照我们想要的顺序进行?

(为什么顺序很重要:A 包含一些表,而 B 包含引用 A 中的表的视图。我们必须确保我们 grant select on A.* to B在尝试create view B.some_view (...) as select ... from A.xyz之前,否则由于权限不足,B的创建失败。)

摸了摸脑袋,翻了下源码,果然非常简单。

SpringLiquibase 实现 InitializingBean 并在 InitializingBean.afterPropertiesSet() 方法中执行 Liquibase 更新。

Spring 在每个 bean 完成初始化后,逐个调用此方法。

因此,要强制执行特定顺序,您需要强制执行 bean 在 Spring 上下文中定义的顺序。最简单的方法是使用 @DependsOn 注释。

所以我们设置了类似的东西:

@Bean
public SpringLiquibase liquibaseA(
    @Qualifier("dataSourceA") DataSource dataSource,
    @Qualifier("liquibasePropertiesA") LiquibaseProperties liquibaseProperties
) {
    return instantiateSpringLiquibase(dataSource, liquibaseProperties); 
}

@Bean
@DependsOn("liquibaseA")
public SpringLiquibase liquibaseB(
    @Qualifier("dataSourceB") DataSource dataSource,
    @Qualifier("liquibasePropertiesB") LiquibaseProperties liquibaseProperties
) {
    return instantiateSpringLiquibase(dataSource, liquibaseProperties); 
}

private SpringLiquibase instantiateSpringLiquibase(DataSource dataSource, LiquibaseProperties liquibaseProperties) {
    // set the datasource from dataSource and everything else from liquibaseProperties
}

这不适用于 spring 引导,但如果您通过更改日志管理迁移,则此解决方法会有所帮助。这假设您对不同的模式有不同的数据源。

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