Spring Boot 2.5.0、Spring Cloud 2020.0.2 和 Hibernate 5.4.31 - H2 数据库多行插入失败

Posted

技术标签:

【中文标题】Spring Boot 2.5.0、Spring Cloud 2020.0.2 和 Hibernate 5.4.31 - H2 数据库多行插入失败【英文标题】:Spring Boot 2.5.0, Spring Cloud 2020.0.2 and Hibernate 5.4.31 - H2 Database Multi Row Insert Failing 【发布时间】:2021-08-11 11:56:38 【问题描述】:

在使用 SB 版本 2.5.0、Spring Cloud 处理 Spring Boot 应用程序时(适用于 Centralized Config 2020.0.2) Hibernate 版本是 5.4.31(我没有使用特定的 Hibernate 版本,它符合 Spring Boot 兼容性)。 使用 H2 数据库存储内存数据,因为我需要创建示例应用程序进行演示。

在 Resources 文件夹中,我确实有我的 SQL 文件。 当我将其命名为data.sql 时,应用程序根本没有启动。 当我将此文件重命名为 import.sql 时,我的应用程序已启动,但仍面临多行插入问题。

数据插入 SQL 文件

/* Data for Entity DataTable */
    INSERT INTO data_table (name) VALUES
    ('Data 1'),
    ('Data 2'),
    ('Data 3');

当我的应用程序使用 Spring Boot 2.3.10.RELEASE 和 Spring Cloud Hoxton.SR5 运行时,这工作得非常好。

我也尝试过 JPA 和 Hibernate 的属性来解决这个问题,但仍然没有成功。查找我使用的属性如下:

spring.jpa.properties.hibernate.jdbc.batch_size=20
spring.jpa.properties.hibernate.order_inserts=true

由于更新了 Spring Boot 和 Spring Cloud 版本,我不确定是否需要特别设置 H2 数据库以用于多行插入。

看起来与 Hibernate 或 H2 数据库问题有关。

WARN 7952 --- [           main] o.h.t.s.i.ExceptionHand lerLoggedImpl    : GenerationTarget encountered exception accepting command : Error executing DDL "('Data 2')" via JDBC Statement

org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "('Data 2')" via JDBC Statement
    at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:67) ~[hibernate-core-5.4.31.Final.jar!/:5.4.31.Final]

...
...
...

Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement "('Data 2'[*]),"; expected "(, WITH, SELECT, TABLE, VALUES"; SQL statement: ('Data 2'), [42001-200]

更新

我已将我的 SQL 文件名恢复为 data.sql,然后我观察到相同的 H2 数据库异常即将到来,并且应用程序无法启动。

在下面找到我得到的启动执行的详细信息:

WARN 4720 --- [           main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSourceScriptDatabaseInitializer' defined in class path resource [org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.class]: Invocation of init method failed; nested exception is org.springframework.jdbc.datasource.init.ScriptStatementFailedException:

Failed to execute SQL script statement #1 of URL [jar:file:/D:/Projects/SpringCloudDemoApp/spring-cloud-demo/target/demo-data-service-0.1.jar!/BOOT-INF/classes!/data.sql]: INSERT INTO data_table (name) VALUES ('Data 1'), ('Data 2'), ('Data 3'); nested exception is org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "DATA_TABLE" not found; SQL statement: INSERT INTO data_table (name) VALUES ('Data 1'), ('Data 2'), ('Data 3') [42102-200]

...
...

ERROR 4720 --- [           main] o.s.boot.SpringApplication               : Application run failed

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSourceScriptDatabaseInitializer' defined in class path resource [org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.class]: Invocation of init method failed; nested exception is org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQLscript statement #1 of URL [jar:file:/D:/Projects/SpringCloudDemoApp/spring-cloud-demo/target/demo-data-service-0.1.jar!/BOOT-INF/classes!/data.sql]: INSERT INTO data_table (name) VALUES ('Data 1'), ('Data 2'), ('Data 3'); nested exception is org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "DATA_TABLE" not found; SQL statement: INSERT INTO data_table (name) VALUES ('Data 1'), ('Data 2'), ('Data 3') [42102-200]

另外请查找我的 Entity 类,以防万一出现问题,但不要认为 Entity 类有什么问题,因为它适用于较旧的 Spring Boot 和 Spring Cloud 版本,但仍在这里分享。

数据表实体类

@Entity
@Table(name = "data_table")
public class DataTable    

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "dataid")
    private Long id;

    @Column(name = "name", nullable = false, unique = true, length = 200)
    private String name;

    // Getter Setters will follow here

应用 YML 文件

server:
    port: 9090
spring:
    datasource:
        url: jdbc:h2:mem:demodb
        driverClassName: org.h2.Driver
        username: scdemo
        password: scdemopass
    jpa:
        properties:
            hibernate:
                dialect: org.hibernate.dialect.H2Dialect
                jdbc:
                    batch_size: 20
                order_inserts: true
    h2:
        console:
            enabled: true
            path: /h2-console
            settings:
                trace: false

重要更新

我也尝试了相同的方法,仅使用 Spring Boot 2.5.0 和 JPA,使用 H2 数据库的 Hibernate,创建了一个示例应用程序,它只有 4 个文件,要启动的 Spring Boot 应用程序文件和实体类 data.sql 为上面,以及用于配置的application.yml,并确保它在相同条件下失败。我确认我在从 data.sql 加载数据以插入时遇到了同样的错误,这适用于较旧的 Spring Boot 版本。

我刚刚将 SB 版本从 2.5.0 更新为 2.3.10.RELEASE,并且相同的代码可以正常工作。

更多详情

    data.sql 文件与 Spring Boot 版本2.3.10.RELEASE 一起使用时,data.sql 文件中的插入语句是多行且位于多行的。它工作得很好。

    data.sql 重命名为import.sql 时,Spring Boot 版本为 2.5.0,import.sql 文件中的插入语句是多行的,但预计将所有值保持在同一行,这也效果很好。

    data.sql 重命名为import.sql,Spring Boot 版本为2.5.0 并且import.sql 文件中的插入语句是多行且位于多行时,此方案将失败。因为它将每个新行上的语句视为 DDL。在这种情况下,应用程序运行,但数据插入不发生。

    GenerationTarget encountered exception accepting command : Error executing DDL "('Data 3')" via JDBC Statement
    

    第 4 种情况是 data.sql 与 Spring Boot 版本 2.5.0data.sql 文件中的插入语句是多行并且在多行上,这种情况也失败了在数据源初始化时和应用程序根本不运行。

分享相同的示例代码: 源代码可以在上面提到的4个条件下尝试: demo-data-service

请提出建议。

【问题讨论】:

有什么问题?插入如何失败? 添加了错误详细信息,这可能会提供一些线索,说明问题出在哪里。我意识到这个问题似乎与 Hibernate 版本或 H2 DB 有关。但不确定,在我更新 Spring Boot 和 Spring Cloud 版本之前,Multi-Row insert 工作正常。 能否将其重命名为 data.sql 并将其放置在 src/main/resources 中,然后再试一次,如果它不起作用,您能否报告启动异常? import.sql 由 Hibernate 处理,而不是 Spring Boot。你能分享你在某个地方的示例应用程序,以便我们自己运行吗? Spring Boot 2.5.0 尝试在应用数据库模式之前运行 data.sql。我必须恢复到 2.4.6 才能正常工作。 【参考方案1】:

您需要将此添加到应用配置中:

spring.jpa.defer-datasource-initialization=true

自 Spring Boot 2.5.0 起,data.sql 默认在 schema 初始化之前执行。

另见:

Spring Boot Data JPA with H2 and data.sql - Table not Found

【讨论】:

真棒@Dan。您在下移到版本2.4.6 的问题中添加的评论以及在此处添加此属性以及版本2.5.0 的答案,这两种解决方案对我来说都很好。非常感谢。 为了从 Spring 中获取更多详细信息,我在 spring 文档中搜索了这个属性并找到了详细信息,所以在这里分享链接 howto data-initialization using-basic-sql-scripts【参考方案2】:

我发现自己在使用 Spring boot 2.5.0 时无法在表名后添加换行符。 使用 Spring Boot 2.5.0,导入脚本应命名为 import.sql

所以,这会引发异常

INSERT into
 TRANSACTIONS (id, account_id, amount, currency, type) VALUES (5, 2, -10.00, 'GBP', 'MONEY_TRANSFER')

虽然没有

INSERT into TRANSACTIONS (id, account_id, amount, currency, type) VALUES (5, 2, -10.00, 'GBP', 'MONEY_TRANSFER')```

【讨论】:

以上是关于Spring Boot 2.5.0、Spring Cloud 2020.0.2 和 Hibernate 5.4.31 - H2 数据库多行插入失败的主要内容,如果未能解决你的问题,请参考以下文章

全网最新 pig 2.5.0发布 !支持Spring Boot 2.2 和 Spring Cloud Hoxton

Spring Boot 2.5.0 重新设计的spring.sql.init 配置有啥用?

Spring Boot 2.5.0 重新设计的spring.sql.init 配置有啥用?

Spring Boot 2.5.0正式版发布,MateCloud微服务平台同步升级

Spring Boot 2.5.0正式版发布,MateCloud微服务平台同步升级

Spring Boot 2.5.0 - REST 控制器,MockMvc 不是 UTF-8