Spring Data JPA(H2 数据库)在表创建期间返回 DDL 错误

jor*_*dan 13 java hibernate h2 spring-data-jpa spring-boot

我有一个 Spring boot 应用程序,其中有H2作为数据库。我只有一个实体,即User. 当我运行该应用程序时,在内存中创建表时不断收到DDL 错误。如果我尝试通过浏览器 ( ) 访问 H2 控制台localhost:8080/h2-console,它将无法连接。我相信这是因为该表未成功创建。

到目前为止,我只向我的实体添加了@Entity, @Id,@GeneratedValue注释User。我什至尝试使用/将字段名称从 ( id, name) 更改为 ( userId, userName) ,因为我认为idname可能是保留字。但是,我不断收到相同的DDL 错误@Column(name="user_id")@Column(name="user_name")

错误:

引起原因:org.h2.jdbc.JdbcSQLSyntaxErrorException:SQL 语句“DROP TABLE IF EXISTS USER[*] CASCADE”中存在语法错误;预期的“标识符”;SQL语句:如果存在用户CASCADE则删除表[42001-206]

2022-01-21 14:28:13.618 WARN 20700 --- [ restartedMain] ohtsiExceptionHandlerLoggedImpl : GenerationTarget 遇到异常接受命令: 执行 DDL 时出错“创建表用户(id 整数不为空,出生日期时间戳,名称 varchar(255),主键(id))”通过 JDBC 语句

org.hibernate.tool.schema.spi.CommandAcceptanceException:通过 JDBC 语句执行 DDL“创建表用户(id 整数不为空,出生日期时间戳,名称 varchar(255),主键(id))”时出错

引起原因:org.h2.jdbc.JdbcSQLSyntaxErrorException:SQL 语句“CREATE TABLE USER[*] (ID INTEGER NOT NULL, BIRTH_DATE TIMESTAMP, NAME VARCHAR(255), PRIMARY KEY (ID))”中存在语法错误;预期的“标识符”;SQL语句:创建表user(id整数不为空,birth_date时间戳,名称varchar(255),主键(id))[42001-206] at org.h2.message.DbException.getJdbcSQLException(DbException.java:521)~ [h2-2.0.206.jar:2.0.206]

用户等级

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.validation.constraints.Past;
import javax.validation.constraints.Size;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

@ApiModel(description="some description here")
@Entity
public class User {
    @Id
    @GeneratedValue
    private Integer id;
    
    @Size(min=2, message="Name should have at least 2 characters")
    @ApiModelProperty(notes="Name should have at least 2 characters")
    private String name;
    
    @Past
    @ApiModelProperty(notes="Birthdate should be in the past")
    @Column(name="birth_date")
    private Date birthDate;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Date getBirthDate() {
        return birthDate;
    }

    public void setBirthDate(Date birthDate) {
        this.birthDate = birthDate;
    }

    @Override
    public String toString() {
        return "User [id=" + id + ", name=" + name + ", birthDate=" + birthDate + "]";
    }

    public User() {}
    
    public User(Integer id, String name, Date birthDate) {
        super();
        this.id = id;
        this.name = name;
        this.birthDate = birthDate;
    }
}
Run Code Online (Sandbox Code Playgroud)

pom.xml 依赖项

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <!-- <version>2.6.2</version> -->
    <version>2.5.2</version>
    <relativePath /> <!-- lookup parent from repository -->
</parent>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>2.0.206</version>
    <scope>runtime</scope>
</dependency>
Run Code Online (Sandbox Code Playgroud)

应用程序属性

logging.level.org.springframework = info
spring.jackson.serialization.write-dates-as-timestamps=false
management.endpoints.web.exposure.include=*

spring.security.user.name=someusername
spring.security.user.password=somepassword

spring.jpa.show-sql=true
spring.h2.console.enabled=true
Run Code Online (Sandbox Code Playgroud)

小智 26

我认为表名“USER”是保留的。如果您使用 @Table(name="") 注释将其更改为“_USER”或“CUSTOM_USER”,它将起作用。


小智 7

更新:我认为有几个因素可能会影响这一点。方言 - 反引号在 org.hibernate.dialect.H2Dialect 或 org.hibernate.dialect.PostgreSQL10Dialect 上似乎不再对我有用。

但是,转义双引号适用于 com.h2database:h2:1.4.200,但不适用于 com.h2database:h2:2.1.210,这似乎支持您在删除版本控制时所看到的内容(默认为较低的临时休眠版本) )。


当我在 hibernate 版本 2.1.210 上运行您的代码时,我也看到了这一点。您正在使用关键字/保留字中的保留字。我之前用过3种解决方案。

这是一个常见问题,特别是对于通用表名称,例如组、顺序、大小写等。

如果您有兴趣保留该名称,可以使用其中一个或两个:

@Table(名称=“用户”)

或者,

@Table(name="`user`") - may not work
Run Code Online (Sandbox Code Playgroud)

或者,使用全局引用的标识符属性

hibernate.globally_quoted_identifiers=true
Run Code Online (Sandbox Code Playgroud)

使用这些将允许您转义 SQL 保留字 - 。我只有一张表有这个问题,所以这些刻度对我有用。您可以通过打开 sql 准备好的语句和格式来验证输出是否正确:

spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true
Run Code Online (Sandbox Code Playgroud)

请求能够在验证下拥有类似这样的属性将是一个很好的功能:

hibernate.hbm2ddl.auto=validate
Run Code Online (Sandbox Code Playgroud)

如果您有兴趣提交错误,您可以在他们的网站上创建一个测试用例并提交,在此处输入链接描述

对我来说奇怪的是为什么从 Maven pom 中删除你的版本有效......这是奇怪的行为。通过将此功能添加到 validate 属性并检查类加载器并循环表 name() 可以轻松地进行预验证。