繁体   English   中英

Spring SQL:org.h2.jdbc.JdbcSQLSyntaxErrorException:SQL 语句中的语法错误“;预期为“标识符”,使用 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', 
'$2a$10$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', 
 '$2a$10$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 语法错误是什么意思,我无法弄清楚。

我尝试使用户中除用户名之外的所有字段都可为空,然后尝试仅使用用户名插入相同的语句,怀疑可能是某些时间戳数据类型是问题所在,但这并没有改变任何事情。

希望有人能帮忙谢谢!

您将表user命名为H2 中的保留关键字 它也是ANSI SQL-99 标准和其他 SQL 实现中的保留关键字(有时它是非保留关键字,例如在 MySQL 中)。

SQL 中的表名如果分隔的话可以使用保留关键字。 H2 支持标准标识符分隔符,即双引号。

我不知道是否有一种简单的方法可以使 Spring 分隔 SQL 语句中的标识符。 我记得它很不稳定。 您必须使用围绕其名称的内置双引号来定义实体,如下所示:

@Entity  
@Table(name = "\"user\"")

参见https://www.chrouki.com/posts/escape-sql-reserved-keywords-jpa-hibernate/

如果您可以避免对表名(或其他标识符,包括列、过程、视图、索引、分区等)使用保留字,那就更容易了。

如果我正确理解你的问题,你正在尝试将 data.sql(mysql 格式)填充到 H2 数据库。

 spring.datasource.url=jdbc:h2:mem:skel;MODE=MYSQL
 spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect

我只是怀疑 H2 能否对此提供足够的支持。 我的建议是提供一个data-h2.sql供你测试。 而且它会很容易维护。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM