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



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

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

错误:

由:org.h2.jdbbc.JdbcSQLSyntaxErrorException引起:中的语法错误SQL语句";DROP TABLE IF EXISTS USER[*]CASCADE";;预期"标识符";;SQL语句:删除表(如果存在)用户CASCADE[44201-206]

2022-01-21 14:28:13.618警告20700---[重述主]o.h.t.s.i.ExceptionHandlerLoggedImpl:GenerationTarget接受命令时遇到异常:执行DDL时出错;创造表用户(id integer不为null,出生日期时间戳,名称varchar(255)、主键(id))";通过JDBC语句

org.hibernate.tool.schema.spi.CommandAcceptanceException:错误执行DDL";创建表用户(id integer不为null,birth_date时间戳,名称varchar(255),主键(id))";通过JDBC语句

由以下原因引起:org.h2.JdbcSQLSyntaxErrorException:中的语法错误SQL语句";创建表用户[*](ID INTEGER不为NULL,BIRTH_DATETIMESTAMP,NAME VARCHAR(255),PRIMARY KEY(ID))";;预期"标识符";;SQL语句:创建表用户(id integer不为null,出生日期时间戳,名称varchar(255),主键(id)[44201-206]在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;
}
}

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>

应用程序属性

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

我认为表名"用户";是保留的。如果你把它改成"_用户";或";CUSTOM_USER";通过使用@Table(name=")注释。

更新:我认为有几个因素可能会影响这一点。方言-在org.hibernate.dialect.H2方言或org.hibernated.dialect.PostgreSQL10Dialect.上,backticks似乎不再适用于我

然而,转义双引号适用于com.h2database:h2:1.4000,但不适用于com.h2数据库:h2:2.1.210,这似乎支持您在删除版本控制时看到的内容(默认为较低的临时hibernate版本)。


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

这是一个常见的问题,尤其是对于通用表名,例如组、顺序、事例等

如果你对保留这个名字感兴趣,你可以使用其中一个或两个:

@表(名称="用户")

或者,

@Table(name="`user`") - may not work

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

hibernate.globally_quoted_identifiers=true

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

spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true

这将是一个很好的功能,请求能够在validate:下拥有这样的属性

hibernate.hbm2ddl.auto=validate

如果你有兴趣提交一个bug,你可以在他们的网站上创建一个测试用例并提交,在这里输入链接描述。

对我来说奇怪的是,为什么从maven pom中删除你的版本有效。。。这是一种奇怪的行为。通过将此功能添加到validate属性中,检查类加载器并在表名()上循环,可以很容易地预先验证这一点。

user关键字在H2的后续版本中保留。

对我来说,这是使用H2 v2.1.212绕过问题:

@Table(name = ""user"")

但这也起了作用(从gtree的回答来看):

@Table(name = "`user`")

我认为有一个默认的表为"用户";所以您必须将表名更改为";用户";或任何其他名称。这对我很有效:-@Table(name = "users")

您很可能会因为使用新版本的H2而出现错误。下面提到的地址中的关键字是保留的,如果使用,将引发编译错误。

http://www.h2database.com/html/advanced.html#keywords

不要使用它们,这样你就可以上路了!

最新更新