BeanCreationException:创建名称为“flywayInitializer”的 bean 时出错

Posted

技术标签:

【中文标题】BeanCreationException:创建名称为“flywayInitializer”的 bean 时出错【英文标题】:BeanCreationException: Error creating bean with name 'flywayInitializer' 【发布时间】:2020-02-07 14:50:19 【问题描述】:

我正在尝试在 docker 容器中运行我的项目测试。在本地运行时,所有测试都可以正常工作。当我尝试将测试移至 docker 容器时,开始出现错误。 这是错误消息:

java.lang.IllegalStateException: Failed to load ApplicationContext
[...]
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flywayInitializer' defined in class path resource [org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]: Invocation of init method failed; nested exception is org.flywaydb.core.internal.command.DbMigrate$FlywayMigrateException: 
Migration V1__initial_user.sql failed
-------------------------------------
SQL State  : 42601
Error Code : 0
Message    : ERROR: syntax error at or near "GENERATED"
  Position: 45
Location   : db/migration/V1__initial_user.sql (/Users/villemossip/Desktop/GRP/GRP-SAS/application/build/resources/main/db/migration/V1__initial_user.sql)
Line       : 36
Statement  : CREATE TABLE revinfo
(
    rev      INTEGER GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ),
    revtstmp BIGINT,
    PRIMARY KEY (rev)
)

从日志中我们可以看到容器镜像已经创建,但是迁移sql schema失败:

[...]
2019-10-10 10:36:18.768  INFO 49547 --- [           main] o.f.c.internal.license.VersionPrinter    : Flyway Community Edition 5.2.4 by Boxfuse
2019-10-10 10:36:18.777  INFO 49547 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2019-10-10 10:36:18.795  INFO 49547 --- [           main] ???? [postgres:9.6.12]                     : Creating container for image: postgres:9.6.12
2019-10-10 10:36:19.001  INFO 49547 --- [           main] ???? [postgres:9.6.12]                     : Starting container with ID: a32dd0850baf34770cce9bdc81918cd4db40502188b85dfaa90f74e2900f9fa7
2019-10-10 10:36:19.547  INFO 49547 --- [           main] ???? [postgres:9.6.12]                     : Container postgres:9.6.12 is starting: a32dd0850baf34770cce9bdc81918cd4db40502188b85dfaa90f74e2900f9fa7
2019-10-10 10:36:23.342  INFO 49547 --- [           main] ???? [postgres:9.6.12]                     : Container postgres:9.6.12 started
2019-10-10 10:36:23.426  INFO 49547 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2019-10-10 10:36:23.431  INFO 49547 --- [           main] o.f.c.internal.database.DatabaseFactory  : Database: jdbc:postgresql://localhost:32834/test (PostgreSQL 9.6)
2019-10-10 10:36:23.488  INFO 49547 --- [           main] o.f.core.internal.command.DbValidate     : Successfully validated 6 migrations (execution time 00:00.024s)
2019-10-10 10:36:23.501  INFO 49547 --- [           main] o.f.c.i.s.JdbcTableSchemaHistory         : Creating Schema History table: "public"."flyway_schema_history"
2019-10-10 10:36:23.519  INFO 49547 --- [           main] o.f.core.internal.command.DbMigrate      : Current version of schema "public": << Empty Schema >>
2019-10-10 10:36:23.520  INFO 49547 --- [           main] o.f.core.internal.command.DbMigrate      : Migrating schema "public" to version 1 - initial user
2019-10-10 10:36:23.542 ERROR 49547 --- [           main] o.f.core.internal.command.DbMigrate      : Migration of schema "public" to version 1 - initial user failed! Changes successfully rolled back.
2019-10-10 10:36:23.546  WARN 49547 --- [           main] o.s.w.c.s.GenericWebApplicationContext   : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flywayInitializer' defined in class path resource [org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]: Invocation of init method failed; nested exception is org.flywaydb.core.internal.command.DbMigrate$FlywayMigrateException: 
Migration V1__initial_user.sql failed
-------------------------------------
[...]

这里是部分sql脚本(app/src/main/resources/db/migration):

[...]
constraint user_aud_pkey primary key (id, rev)
);

CREATE TABLE revinfo
(
    rev      INTEGER GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ),
    revtstmp BIGINT,
    PRIMARY KEY (rev)
);

CREATE SEQUENCE hibernate_sequence INCREMENT 1 MINVALUE 1
    MAXVALUE 9223372036854775807
    START 1
    CACHE 1;

这里是“application.properties”(app/test/java/resources):

spring.datasource.driver-class-name=org.testcontainers.jdbc.ContainerDatabaseDriver
spring.datasource.url=jdbc:tc:postgresql://localhost:5433/test
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=validate
spring.jackson.default-property-inclusion=NON_NULL

spring.flyway.baselineOnMigrate=true
spring.flyway.check-location=true
spring.flyway.locations=classpath:db/migration
spring.flyway.schemas=public
spring.flyway.enabled=true

我也在同一个目录下有 container-license-acceptance.txt 文件。

在“build.gradle”中我添加了以下几行(app/build.gradle):

dependencies 
    [...]
    testImplementation "org.testcontainers:junit-jupiter:1.11.3"
    testImplementation "org.testcontainers:postgresql:1.11.3"


在 BaseInitTest 文件中,我有以下几行 (app/test/java/com):

@Testcontainers
@SpringBootTest
public class BaseIntTest 

    @Container
    private static final PostgreSQLContainer<?> container = new PostgreSQLContainer<>();

    [...]

我不明白,相同的测试如何一开始通过,但当我将它们移动到 docker 容器时却失败了?

【问题讨论】:

我认为您应该检查数据库详细信息是否正确,并且您可以使用以下脚本创建表(而不是使用外部任何编辑器从代码创建表)创建表 revinfo(rev INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1), revtstmp BIGINT, PRIMARY KEY (rev));错误是指向查询中的语法错误 我通过 pgAdmin 4 运行查询,在那里我创建了新数据库并执行了相同的查询,响应为:“CREATE TABLE 查询在 77 毫秒内成功返回。” 确保您使用相同版本的 Postgres 进行测试。您似乎在 Docker 中使用了相当旧的版本。 可能是因为docker在创建容器postgres:9.6.12时,与sql脚本不兼容? 不要创建新数据库尝试使用现有数据库。尝试从容器运行代码时,在运行代码之前创建空数据库(不要保留任何表)。 【参考方案1】:

看起来带有数据库的测试容器已经成功启动,所以没有问题,你得到的是一个空数据库。

然后您尝试运行飞行路线,但失败了。 Spring Boot 中的 Flyway 在 Spring 应用程序上下文的初始化期间工作, 因此实际迁移在应用程序上下文初始化时运行,因此迁移失败看起来像弹簧失败。

但是记录了原因:迁移文件的内容无效:

Migration V1__initial_user.sql failed
-------------------------------------
SQL State  : 42601
Error Code : 0
Message    : ERROR: syntax error at or near "GENERATED"
 Position: 45
Location   : db/migration/V1__initial_user.sql (/Users/villemossip/Desktop/GRP/GRP- 
SAS/application/build/resources/main/db/migration/V1__initial_user.sql)
Line       : 36
Statement  : CREATE TABLE revinfo
(
   rev      INTEGER GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ),
   revtstmp BIGINT,
   PRIMARY KEY (rev)
)

GENERATED BY 不受支持。

为什么?可能您的 docker 映像包含不支持此语法的 RDBMS 版本。所以它不同于你在没有docker的本地环境中使用的DB。

无论如何,这与 docker、spring 或 flyway 无关,而是与数据库和迁移代码有关。

在分辨率方面,我建议直接运行DB的docker镜像(不带java、testcontainers和flyway)。 当它运行时,只需在 pgadmin 或其他东西中“手动”运行此迁移。您应该会看到同样的错误。

【讨论】:

【参考方案2】:

谢谢@M. Deinum 和Mark Bramnik!

我发现问题出在 Postgres 版本上。出于某种原因,默认情况下 docker 映像是使用旧版本 9.6.12 创建的,但 sql 脚本 GENERATED BY DEFAULT 已添加到 Postgres 版本 10。

解决方案 1(将 sql 脚本更新为旧版本):

CREATE TABLE revinfo
(
    rev      INTEGER PRIMARY KEY NOT NULL,
    revtstmp BIGINT
);

解决方案 2: 通过在项目中创建 CustomPostgreSQLContainer 文件将 docker 镜像版本更改为 11.2。

import org.testcontainers.containers.PostgreSQLContainer;

public class CustomPostgreSQLContainer extends PostgreSQLContainer<CustomPostgreSQLContainer> 
    private static final String IMAGE_VERSION = "postgres:11.2";
    private static CustomPostgreSQLContainer container;
    CustomPostgreSQLContainer() 
        super(IMAGE_VERSION);
    
    public static CustomPostgreSQLContainer getInstance() 
        if (container == null) 
            container = new CustomPostgreSQLContainer();
        
        return container;
    
    @Override
    public void start() 
        super.start();
        System.setProperty("spring.datasource.url", container.getJdbcUrl());
        System.setProperty("spring.datasource.username", container.getUsername());
        System.setProperty("spring.datasource.password", container.getPassword());
    
    @Override
    public void stop() 
        //do nothing, JVM handles shut down
    

并更新 BaseIntTest 文件:

@Testcontainers
@SpringBootTest
public class BaseIntTest 

    @Container
    private static final PostgreSQLContainer<?> container = CustomPostgreSQLContainer.getInstance();

最后从测试 application.properties 文件中删除两行:

spring.datasource.driver-class-name=org.testcontainers.jdbc.ContainerDatabaseDriver
spring.datasource.url=jdbc:tc:postgresql://localhost:5433/test

【讨论】:

【参考方案3】:

我的问题是因为使用了spring.datasource.url=jdbc:postgres://localhost:5432/todoListDb 代替 spring.datasource.url=jdbc:postgresql://localhost:5432/todoListDb

(postgres 而不是 PostgreSQL)在我的 application.properties 文件中

因此,请尝试为您的数据库使用正确的 URL,并验证您的 url 中是否存在拼写错误

【讨论】:

【参考方案4】:

此问题的一个原因是缺少 docker DB 版本:2.0.1

通过添加这个特定版本,它对我有用。

【讨论】:

以上是关于BeanCreationException:创建名称为“flywayInitializer”的 bean 时出错的主要内容,如果未能解决你的问题,请参考以下文章

创建 ElasticSearchRepository 时出现 BeanCreationException - 无法解析匹配的构造函数

org.springframework.beans.factory.BeanCreationException:创建定义名称“requestMappingHandlerMapping”的bean时出错

org.springframework.beans.factory.BeanCreationException:创建名为“employeeRepo”的bean时出错:

异常:org.springframework.beans.factory.BeanCreationException:创建名为“org.springframework.security.filterC

Spring Boot 项目“org.springframework.beans.factory.BeanCreationException:创建名为“entityManagerFactory”的be

Spring Boot - org.springframework.beans.factory.BeanCreationException:使用名称创建 bean 时出错