Spring SQL: org.h2.jdbc.JdbcSQLSyntaxErrorException: SQL 语句中的语法错误;预期 "identifier",使用 INSERT INTO 时
Spring SQL: org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement "; expected "identifier", when using INSERT INTO
我正在开发 Spring Web 应用程序。
我正在使用 mysql 数据库,但是对于我的单元测试,我想在 H2 数据库中 运行 它们。
测试特定的应用程序属性:
#Specific spring boot configuration for tests
spring.main.banner-mode=off
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:skel;MODE=MYSQL
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
spring.datasource.user=sa
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=create
spring.jpa.defer-datasource-initialization=true
endpoints.enabled=false
# enable test-profile
spring.profiles.active=test
如您所见,我的数据库使用 MODE=MYSQL,因为我的 data.sql 使用 MySQL 方言。
但是在 data.sql 的初始化期间我得到这个错误:
Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement
"INSERT IGNORE INTO [*]user (username, password, first_name, last_name, enabled,
news_cycle, created_at, updated_at) VALUES('admin@example.com',
'a$BFNo8gUTorQMtikcFbYVEeAPyX5iCn5BpKglp.eJ2DrFs.bNeXgEu', 'Admin', 'Adminoso',
'TRUE', 'NEVER', '2016-01-01 00:00:00', '2016-01-01 00:00:00')"; expected
"identifier"; SQL statement:
INSERT IGNORE INTO user (username, password, first_name, last_name, enabled,
news_cycle, created_at, updated_at) VALUES('admin@example.com',
'a$BFNo8gUTorQMtikcFbYVEeAPyX5iCn5BpKglp.eJ2DrFs.bNeXgEu', 'Admin', 'Adminoso',
'TRUE', 'NEVER', '2016-01-01 00:00:00', '2016-01-01 00:00:00') [42001-212]
我想您可以从这个错误中看出导致问题的 SQL 语句,data.sql 中的其他语句似乎不会导致问题。例如:
INSERT IGNORE INTO department (department_id, department_name, created_at,
updated_at) VALUES (1, 'Marketing', '2016-01-01 00:00:00', '2016-01-01 00:00:00');
我的用户实体:
import at.qe.skeleton.model.facility.Department;
import at.qe.skeleton.model.facility.Room;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.Objects;
import java.util.Set;
/**
* Entity representing users.
*
* This class is part of the skeleton project provided for students of the
* courses "Software Architecture" and "Software Engineering" offered by the
* University of Innsbruck.
*/
@Getter
@Setter
@Entity
@EntityListeners(AuditingEntityListener.class)
public class User implements Comparable<User>{
@Id
@Column(name = "username", length = 255)
private String username;
@Column(name = "password",nullable = false,length = 255)
private String password;
@Column(name = "first_Name",nullable = false,length = 255)
private String firstName;
@Column(name = "last_Name",nullable = false,length = 255)
private String lastName;
@Column(name = "enabled", nullable = false)
private boolean enabled;
@Column(name = "news_cycle", nullable = false)
@Enumerated(EnumType.STRING)
private NewsletterCycle newsCycle;
@ElementCollection(targetClass = UserRole.class, fetch = FetchType.EAGER)
@CollectionTable(name = "user_roles")
@Enumerated(EnumType.STRING)
private Set<UserRole> roles;
@ManyToOne
@JoinColumn(name = "department_id")
private Department department;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "manages_department_id", referencedColumnName = "department_id")
private Department managingDepartment;
@ManyToOne
@JoinColumn(name = "assigned_room_id")
private Room assignedRoom;
@OneToMany(mappedBy = "user", cascade = CascadeType.REMOVE, fetch = FetchType.EAGER)
private Set<Absence> absences;
@CreatedDate
@Column(name = "created_at", nullable = false)
private LocalDateTime created;
@LastModifiedDate
@Column(name = "updated_at", nullable = false)
private LocalDateTime updated;
@Override
public int compareTo(User o) {
return this.username.compareTo(o.getUsername());
}
@Override
public int hashCode() {
int hash = 7;
hash = 59 * hash + Objects.hashCode(this.getUsername());
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!(obj instanceof User)) {
return false;
}
final User other = (User) obj;
return Objects.equals(this.username, other.getUsername());
}
@Override
public String toString() {
return "username: " + getUsername() + " name: " + getFirstName() + " " + getLastName();
}
}
在这种情况下,这个“预期的标识符”SQL 语法错误是什么意思,我无法理解。
我尝试将用户中除用户名以外的所有字段设置为可为空,然后尝试仅插入用户名的相同语句,怀疑可能是某些时间戳数据类型有问题,但这并没有改变任何事情。
希望有人能帮忙谢谢!
如果我正确理解你的问题,你正在尝试
将 data.sql(mysql 格式)填充到 H2 数据库。
spring.datasource.url=jdbc:h2:mem:skel;MODE=MYSQL
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
我只是怀疑H2能否在这方面得到足够的支持。
我的建议是为您的测试提供一个数据-h2.sql。而且维护起来也很方便。
您将 table user
命名为 reserved keyword in H2. It's also a reserved keyword in the ANSI SQL-99 standard 并且经常出现在其他 SQL 实现中(有时它是 non-reserved 关键字,例如在 MySQL).
您可以使用保留关键字作为 SQL 中的 table 名称,如果您分隔它们。 H2 支持标准标识符分隔符,即 double-quotes.
我不知道是否有一种简单的方法可以使 Spring 分隔 SQL 语句中的标识符。我记得它很不稳定。您必须在其名称周围使用 built-in double-quotes 来定义实体,如下所示:
@Entity
@Table(name = "\"user\"")
见https://www.chrouki.com/posts/escape-sql-reserved-keywords-jpa-hibernate/
如果您可以避免为您的 table 名称(或其他标识符,包括列、过程、视图、索引、分区等)使用保留字,那就更容易了。
我正在开发 Spring Web 应用程序。 我正在使用 mysql 数据库,但是对于我的单元测试,我想在 H2 数据库中 运行 它们。
测试特定的应用程序属性:
#Specific spring boot configuration for tests
spring.main.banner-mode=off
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:skel;MODE=MYSQL
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
spring.datasource.user=sa
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=create
spring.jpa.defer-datasource-initialization=true
endpoints.enabled=false
# enable test-profile
spring.profiles.active=test
如您所见,我的数据库使用 MODE=MYSQL,因为我的 data.sql 使用 MySQL 方言。
但是在 data.sql 的初始化期间我得到这个错误:
Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement
"INSERT IGNORE INTO [*]user (username, password, first_name, last_name, enabled,
news_cycle, created_at, updated_at) VALUES('admin@example.com',
'a$BFNo8gUTorQMtikcFbYVEeAPyX5iCn5BpKglp.eJ2DrFs.bNeXgEu', 'Admin', 'Adminoso',
'TRUE', 'NEVER', '2016-01-01 00:00:00', '2016-01-01 00:00:00')"; expected
"identifier"; SQL statement:
INSERT IGNORE INTO user (username, password, first_name, last_name, enabled,
news_cycle, created_at, updated_at) VALUES('admin@example.com',
'a$BFNo8gUTorQMtikcFbYVEeAPyX5iCn5BpKglp.eJ2DrFs.bNeXgEu', 'Admin', 'Adminoso',
'TRUE', 'NEVER', '2016-01-01 00:00:00', '2016-01-01 00:00:00') [42001-212]
我想您可以从这个错误中看出导致问题的 SQL 语句,data.sql 中的其他语句似乎不会导致问题。例如:
INSERT IGNORE INTO department (department_id, department_name, created_at,
updated_at) VALUES (1, 'Marketing', '2016-01-01 00:00:00', '2016-01-01 00:00:00');
我的用户实体:
import at.qe.skeleton.model.facility.Department;
import at.qe.skeleton.model.facility.Room;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.Objects;
import java.util.Set;
/**
* Entity representing users.
*
* This class is part of the skeleton project provided for students of the
* courses "Software Architecture" and "Software Engineering" offered by the
* University of Innsbruck.
*/
@Getter
@Setter
@Entity
@EntityListeners(AuditingEntityListener.class)
public class User implements Comparable<User>{
@Id
@Column(name = "username", length = 255)
private String username;
@Column(name = "password",nullable = false,length = 255)
private String password;
@Column(name = "first_Name",nullable = false,length = 255)
private String firstName;
@Column(name = "last_Name",nullable = false,length = 255)
private String lastName;
@Column(name = "enabled", nullable = false)
private boolean enabled;
@Column(name = "news_cycle", nullable = false)
@Enumerated(EnumType.STRING)
private NewsletterCycle newsCycle;
@ElementCollection(targetClass = UserRole.class, fetch = FetchType.EAGER)
@CollectionTable(name = "user_roles")
@Enumerated(EnumType.STRING)
private Set<UserRole> roles;
@ManyToOne
@JoinColumn(name = "department_id")
private Department department;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "manages_department_id", referencedColumnName = "department_id")
private Department managingDepartment;
@ManyToOne
@JoinColumn(name = "assigned_room_id")
private Room assignedRoom;
@OneToMany(mappedBy = "user", cascade = CascadeType.REMOVE, fetch = FetchType.EAGER)
private Set<Absence> absences;
@CreatedDate
@Column(name = "created_at", nullable = false)
private LocalDateTime created;
@LastModifiedDate
@Column(name = "updated_at", nullable = false)
private LocalDateTime updated;
@Override
public int compareTo(User o) {
return this.username.compareTo(o.getUsername());
}
@Override
public int hashCode() {
int hash = 7;
hash = 59 * hash + Objects.hashCode(this.getUsername());
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!(obj instanceof User)) {
return false;
}
final User other = (User) obj;
return Objects.equals(this.username, other.getUsername());
}
@Override
public String toString() {
return "username: " + getUsername() + " name: " + getFirstName() + " " + getLastName();
}
}
在这种情况下,这个“预期的标识符”SQL 语法错误是什么意思,我无法理解。
我尝试将用户中除用户名以外的所有字段设置为可为空,然后尝试仅插入用户名的相同语句,怀疑可能是某些时间戳数据类型有问题,但这并没有改变任何事情。
希望有人能帮忙谢谢!
如果我正确理解你的问题,你正在尝试 将 data.sql(mysql 格式)填充到 H2 数据库。
spring.datasource.url=jdbc:h2:mem:skel;MODE=MYSQL
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
我只是怀疑H2能否在这方面得到足够的支持。 我的建议是为您的测试提供一个数据-h2.sql。而且维护起来也很方便。
您将 table user
命名为 reserved keyword in H2. It's also a reserved keyword in the ANSI SQL-99 standard 并且经常出现在其他 SQL 实现中(有时它是 non-reserved 关键字,例如在 MySQL).
您可以使用保留关键字作为 SQL 中的 table 名称,如果您分隔它们。 H2 支持标准标识符分隔符,即 double-quotes.
我不知道是否有一种简单的方法可以使 Spring 分隔 SQL 语句中的标识符。我记得它很不稳定。您必须在其名称周围使用 built-in double-quotes 来定义实体,如下所示:
@Entity
@Table(name = "\"user\"")
见https://www.chrouki.com/posts/escape-sql-reserved-keywords-jpa-hibernate/
如果您可以避免为您的 table 名称(或其他标识符,包括列、过程、视图、索引、分区等)使用保留字,那就更容易了。