具有 Spring 引导和多个模式的 Liquibase,如何指定执行顺序
Liquibase with Spring Boot and multiple schemas, how to specify execution order
我们有一个数据迁移作业需要按顺序初始化架构 A
和 B
。我们通过定义多个 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>
我们有一个数据迁移作业需要按顺序初始化架构 A
和 B
。我们通过定义多个 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>