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

Man*_*dit 5 java hibernate jpa h2 spring-boot

在使用 SB 版本 2.5.0、Spring Cloud(用于集中配置 2020.0.2)开发 Spring Boot 应用程序时,Hibernate 版本为 5.4.31(我没有使用特定的 Hibernate 版本,它是根据 Spring Boot 兼容性)。使用 H2 数据库作为内存数据,因为我需要创建用于演示的示例应用程序。

在资源文件夹中,我确实有我的 SQL 文件。当我命名它时,data.sql应用程序根本不会启动。当我将此文件重命名为 时import.sql,我的应用程序启动了,但仍然面临多行插入问题。

数据插入SQL文件

/* Data for Entity DataTable */
    INSERT INTO data_table (name) VALUES
    ('Data 1'),
    ('Data 2'),
    ('Data 3');
Run Code Online (Sandbox Code Playgroud)

当我的应用程序使用 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
Run Code Online (Sandbox Code Playgroud)

由于更新了 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]
Run Code Online (Sandbox Code Playgroud)

更新

我已将 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]
Run Code Online (Sandbox Code Playgroud)

另外,请找到我的实体类,以防出现问题,但不要认为实体类有任何问题,因为它与较旧的 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
}
Run Code Online (Sandbox Code Playgroud)

应用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
Run Code Online (Sandbox Code Playgroud)

重要更新

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

我刚刚将 SB 版本从 更新到2.5.02.3.10.RELEASE并且相同的代码有效。

更多细节

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

  2. 当使用 Spring Boot 版本 2.5.0data.sql重命名为 时import.sql,文件中的插入语句import.sql是多行的,但预计将所有值保留在同一行上,这也可以很好地工作。

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

    GenerationTarget encountered exception accepting command : Error executing DDL "('Data 3')" via JDBC Statement
    
    Run Code Online (Sandbox Code Playgroud)
  4. 第四种情况是,当data.sql使用 Spring Boot 版本2.5.0并且文件中的插入语句data.sql是多行且位于多行时,这种情况也会失败。在数据源初始化时,应用程序根本不运行。

共享示例代码:满足上述 4 个条件即可尝试源代码: demo-data-service

请建议。

Dan*_*Dan 5

您需要将其添加到应用程序配置中:

spring.jpa.defer-datasource-initialization=true
Run Code Online (Sandbox Code Playgroud)

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

也可以看看:

使用 H2 和 data.sql 的 Spring Boot Data JPA - 找不到表