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

在使用 SB 2.5.0 版 Spring 启动应用程序时,Spring 云(用于集中配置 2020.0.2) Hibernate 版本是 5.4.31(我没有使用特定的 Hibernate 版本,它是根据 Spring 启动兼容性)。 使用 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 引导和 Spring 云版本,我不确定是否有什么特别需要设置 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]

另外请找到我的实体 class 以防出现问题,但不要认为实体 class 有任何问题,因为它适用于较旧的 Spring 引导和Spring 云版本,但仍然在这里分享。

数据表实体Class

@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,Hibernate with H2 Database,创建了一个只有 4 个文件的示例应用程序,Spring Boot Application 文件到启动和实体 class、data.sql 如上所述,以及 application.yml 用于配置,并确保它在相同条件下失败。我确认我在从 data.sql 加载数据以插入时遇到相同的错误,这适用于较旧的 Spring 引导版本。

我刚刚将 SB 版本从 2.5.0 更新到 2.3.10.RELEASE,同样的代码也能正常工作。

更多详情:

  1. data.sql文件与Spring引导版本2.3.10.RELEASE一起使用时,data.sql文件中的Insert语句是多行和在多条线上。它工作得很好。

  2. data.sql重命名为import.sql时,与Spring引导版本2.5.0和import.sql文件中的Insert Statements是多-row 但希望将所有值保持在同一行,这也很有效。

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

    GenerationTarget encountered exception accepting command : Error executing DDL "('Data 3')" via JDBC Statement
    
  4. 而第 4 种情况是 data.sql 与 Spring 引导版本 2.5.0data.sql 文件中的插入语句是多行的并且在多行上,这种情况也失败了在数据源初始化和应用程序时根本没有运行。

分享相同的示例代码: 满足上述4个条件可以尝试源码: demo-data-service

求推荐。

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

spring.jpa.defer-datasource-initialization=true

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

另请参阅:

我发现自己使用 Spring boot 2.5.0 时无法在 table 名称后添加换行符。 使用 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')```