Search code examples
javaspringpostgresqlliquibase

Prevent Liquibase migrating public schema in Postgres and only migrate configured schemas


I'm using org.postgresql:postgresql:42.1.4 with an instance of the official Postgres Docker image running via docker-compose.

The database has the public schema by default, and I manually create schemas; 001 and 002 each for a separate tenant.

The problem is that on application start-up, Liquibase executes the changelogs against public.

How I can get Liquibase to only execute the changelogs against the 2 configured schemas? i.e 001 and 002

My Liquibase configuration to run migration changelogs on application start-up:

@Configuration
@EnableConfigurationProperties({LiquibaseProperties.class})
public class LiquibaseConfiguration {

  private final Logger log = LoggerFactory.getLogger(LiquibaseConfiguration.class);

  private final Environment env;

  public LiquibaseConfiguration(Environment env) {
    this.env = env;
  }

  @Bean
  public SpringLiquibase liquibase(@Qualifier("taskExecutor") TaskExecutor taskExecutor,
      DataSource dataSource, LiquibaseProperties liquibaseProperties) {
    SpringLiquibase liquibase = new SpringLiquibase();
    liquibase.setDataSource(dataSource);
    liquibase.setChangeLog("config/liquibase/changelog/changelog-root.xml");
    return liquibase;
  }

  @Bean
  @DependsOn("liquibase") // ensure execution after SpringLiquibase Bean
  public MultiTenantSpringLiquibase liquibaseMt(DataSource dataSource, LiquibaseProperties liquibaseProperties) {

    MultiTenantSpringLiquibase liquibase = new MultiTenantSpringLiquibase();
    liquibase.setDataSource(dataSource);
    liquibase.setChangeLog("config/liquibase/changelog/changelog-root.xml");
    liquibase.setSchemas(Arrays.asList("001", "002"));
    return liquibase;
  }
}

And a default DataSource:

@Configuration
public class DataSourceConfig {

  @Bean
  public DataSource getDataSource() {
    DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
    dataSourceBuilder.driverClassName("org.postgresql.Driver");
    dataSourceBuilder.url("jdbc:postgresql://localhost:5432/postgres");
    dataSourceBuilder.username("postgres");
    dataSourceBuilder.password("");
    return dataSourceBuilder.build();
  }
}

Solution

  • The problem you have is the fact that SpringLiquibase will by default auto run the changelog on the configured datasource, and for Postgres if no schema is specified the SQL scripts will be executed on the public aka default schema. So you have two choices to do to stop liquibase from auto-executing against the default schema.

    1. Just disable the autorun on SpringLiquibase. There is a specific configuration property which can be used to disable/enable the autorun functionality. The property name is shouldRun. So just set the value to false and the changelog will not be executed against the default schema.

      @Bean
      public SpringLiquibase liquibase(@Qualifier("taskExecutor") TaskExecutor taskExecutor,
      DataSource dataSource, LiquibaseProperties liquibaseProperties) {
        SpringLiquibase liquibase = new SpringLiquibase();
        liquibase.setDataSource(dataSource);
        liquibase.setChangeLog("config/liquibase/changelog/changelog-root.xml");
        // here we tell the system not to run by default
        liquibase.setShouldRun(false);
        return liquibase;
      }
      
    2. You can totally disable default functionality for spring liquibase by excluding the LiquibaseAutoConfiguration and just creating the MultiTenantSpringLiquibase bean and delete the SpringLiquibase bean creation.

    To disable spring liquibase auto-configuration exclude the LiquibaseAutoConfiguration

    @SpringBootApplication(exclude={LiquibaseAutoConfiguration.class}) 
    

    Delete the creation of SpringLiquibase bean.

    @Configuration
    @EnableConfigurationProperties({LiquibaseProperties.class})
    public class LiquibaseConfiguration {
    
      @Bean
      public MultiTenantSpringLiquibase liquibaseMt(DataSource dataSource, LiquibaseProperties liquibaseProperties) {
    
        MultiTenantSpringLiquibase liquibase = new MultiTenantSpringLiquibase();
        liquibase.setDataSource(dataSource);
        liquibase.setChangeLog("config/liquibase/changelog/changelog-root.xml");
        liquibase.setSchemas(Arrays.asList("001", "002"));
        return liquibase;
      }
    }