You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot中Flyway执行migrate时报schema不存在错误

Flyway创建flyway_schema_history表时提示schema不存在问题排查

问题场景

已在首个Flyway迁移脚本中添加create schema if not exists testit authorization sa语句,但Flyway执行时仍报错找不到testit schema,无法创建历史记录表。


配置与日志信息

application-test.yml配置

spring:
  flyway:
    enabled: true
    create-schemas: true
    default-schema: testit
    driver-class-name: org.postgresql.Driver
    user: sa
    password: sa
    schemas: testit
    locations: filesystem:database/postgres/testit/testit
    tablespace: testit
  r2dbc:
    pool:
      initialSize: 1
      maxSize: 2
      maxIdleTime: 120000

错误日志

SQL State  : 3F000
Error Code : 0
Message    : ERROR: schema "testit" does not exist
  Position: 14
Location   :  ()
Line       : 1
Statement  : CREATE TABLE "testit"."flyway_schema_history" (
    "installed_rank" INT NOT NULL,
    "version" VARCHAR(50),
    "description" VARCHAR(200) NOT NULL,
    "type" VARCHAR(20) NOT NULL,
    "script" VARCHAR(1000) NOT NULL,
    "checksum" INTEGER,
    "installed_by" VARCHAR(100) NOT NULL,
    "installed_on" TIMESTAMP NOT NULL DEFAULT now(),
    "execution_time" INTEGER NOT NULL,
    "success" BOOLEAN NOT NULL
) TABLESPACE "testit"

build.gradle依赖配置

核心依赖

Spring boot version - 2.7.11
Java version - 17

testImplementation('org.flywaydb:flyway-core')
testImplementation('org.springframework:spring-jdbc:5.3.8')
implementation 'org.springframework.boot:spring-boot-starter-data-r2dbc'
implementation 'org.postgresql:r2dbc-postgresql'
implementation 'io.r2dbc:r2dbc-pool'
runtimeOnly ('org.postgresql:postgresql')

TestContainers依赖

testContainerVersion = "1.18.3"

testImplementation("org.testcontainers:testcontainers:$testContainerVersion")
testImplementation("org.testcontainers:junitjupiter:$testContainerVersion") 
testImplementation("org.testcontainers:postgresql:$testContainerVersion") 
testImplementation("org.testcontainers:r2dbc:$testContainerVersion") 

TestContainer配置类

@Testcontainers
public class ContainersConfig {

    @Container
    static PostgreSQLContainer<?> postgresContainer =
            new PostgreSQLContainer<>(DockerImageName.parse("postgres:14.6"))
                    .withDatabaseName("testit")
                    .withUsername("sa")
                    .withPassword("sa");

    @AfterAll
    void stopContainer() {
        postgresContainer.stop();
    }
    static {
        Startables.deepStart(postgresContainer).join();
    }

    @DynamicPropertySource
    private static void setDatasourceProperties(DynamicPropertyRegistry registry) {

        registry.add("spring.r2dbc.url", () ->
                "r2dbc:postgresql://"+ postgresContainer.getHost() + ":" +
                        postgresContainer.getMappedPort(PostgreSQLContainer.POSTGRESQL_PORT)
                + "/" + postgresContainer.getDatabaseName());
        registry.add("spring.r2dbc.username", postgresContainer::getUsername);
        registry.add("spring.r2dbc.password", postgresContainer::getPassword);
        registry.add("spring.flyway.url", postgresContainer::getJdbcUrl);
    }
}

排查思路与解决方案

核心原因

Flyway在执行迁移脚本之前,会优先尝试创建flyway_schema_history表来记录迁移状态。此时用户编写的迁移脚本尚未执行,testitschema还未被创建,因此触发报错。

虽然配置了create-schemas: true,但结合PostgreSQL特性,仍可能因以下原因失败:

  1. JDBC连接URL指向testit数据库,但该数据库默认不存在testitschema(PostgreSQL默认schema为public);
  2. 连接用户sa缺乏创建schema的权限,导致create-schemas配置未生效。

解决方案

方案1:通过Flyway初始化SQL提前创建schema

在application-test.yml的Flyway配置中添加init-sql参数,让JDBC连接建立后立即执行schema创建语句:

spring:
  flyway:
    # 其他配置保持不变
    init-sql: "CREATE SCHEMA IF NOT EXISTS testit AUTHORIZATION sa;"

该语句会在Flyway创建历史表之前执行,确保schema存在。

方案2:修改JDBC连接URL指定默认schema

将Flyway的JDBC连接URL修改为:

jdbc:postgresql://localhost:49165/testit?currentSchema=testit

保留create-schemas: true配置,Flyway会自动创建不存在的schema(需确保sa用户有权限)。

方案3:在TestContainer启动时提前创建schema

修改TestContainer的静态初始化逻辑,手动执行schema创建SQL:

static {
    Startables.deepStart(postgresContainer).join();
    // 提前创建schema
    try (Connection conn = DriverManager.getConnection(
            postgresContainer.getJdbcUrl(),
            postgresContainer.getUsername(),
            postgresContainer.getPassword())) {
        try (Statement stmt = conn.createStatement()) {
            stmt.execute("CREATE SCHEMA IF NOT EXISTS testit AUTHORIZATION sa;");
        }
    } catch (SQLException e) {
        throw new RuntimeException("Failed to create schema", e);
    }
}

确保Flyway启动前,schema已存在。

额外注意事项

  • 确认sa用户拥有创建schema的权限,若为普通用户,需执行授权语句:GRANT CREATE SCHEMA ON DATABASE testit TO sa;
  • 检查迁移脚本命名符合Flyway规范(如V1__create_schema.sql),确保Flyway能正确识别并执行首个脚本。

内容的提问来源于stack exchange,提问作者Sooraj V

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 10:50:03