51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

在 Spring Boot 中使用 H2 异常:JdbcSQLSyntaxErrorException

1、概览 {#1概览}

在 Spring Boot 中使用 h2 作为内存数据库的时候遇到异常:org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement expected "identifier"。

本文将会介绍出现 org.h2.jdbc.JdbcSQLSyntaxErrorException 的原因以及解决方案。

2、原因 {#2原因}

通常,H2 会抛出 JdbcSQLSyntaxErrorException 来提示 SQL 语句中的语法错误。其中,"expected identifier" 信息表明 SQL 期望一个合适的 标识符,而我们没有给出。

导致这种异常的最常见原因是使用保留关键字作为标识符。

例如,使用关键字 table 来命名特定的 SQL 表就会导致 JdbcSQLSyntaxErrorException

另一个原因是在 SQL 语句中缺少或错用了关键字。

3、重现异常 {#3重现异常}

作为开发者,我们经常使用 user 一词来表示用户表。不幸的是,它在 H2 中是一个 保留关键字

为了重现异常,我们将故意使用关键字 user

因此,首先让我们添加一个基本的 SQL 脚本来初始化 H2 数据库并为其添加数据:

INSERT INTO user VALUES (1, 'admin', 'p@ssw@rd'); 
INSERT INTO user VALUES (2, 'user', 'userpasswd');

接下来,我们将创建一个实体(Entity)类来映射 user 表:

@Entity
public class User {

    @Id
    private int id;
    private String login;
    private String password;

    // get/set 方法省略
}

请注意,@Entity 是一个 JPA 注解,用于将一个类标识为实体类。

此外,@Id 表示映射数据库主键的字段。

现在,如果我们启动程序,Spring Boot 将出现以下异常:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSourceScriptDatabaseInitializer' 
...
nested exception is org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement "INSERT INTO [*]user VALUES (1, 'admin', 'p@ssw@rd')"; expected "identifier"; SQL statement:
INSERT INTO user VALUES (1, 'admin', 'p@ssw@rd') [42001-214]
...

我们可以从日志中看到,H2 对 insert 语句抛出了异常,因为关键字 user 是保留的,不能用作标识符。

4、解决方案 {#4解决方案}

要修复异常,我们需要确保不使用 SQL 保留关键字作为标识符。

或者,我们可以使用引号将其转义。

因此,首先,让我们给关键字 user 加上双引号:

INSERT INTO "user" VALUES (1, 'admin', 'p@ssw@rd');
INSERT INTO "user" VALUES (2, 'user', 'userpasswd');

接下来,我们将为实体 User 创建一个 JPA repository:

@Repository
public interface UserRepository extends JpaRepository<User, Integer> {
}

现在,让我们添加一个测试用例,以确认是否正常:

@Test
public void givenValidInitData_whenCallingFindAll_thenReturnData() {
    List<User> users = userRepository.findAll();

    assertThat(users).hasSize(2);
}

如上所示,findAll() 成功执行,没有出现 JdbcSQLSyntaxErrorException 异常。

另一种避免异常的方法是在 JDBC URL 中添加 NON_KEYWORDS=user

spring.datasource.url=jdbc:h2:mem:mydb;NON_KEYWORDS=user

这样,我们就可以告诉 H2 从保留字列表中排除 user 关键字。

如果我们使用的是 Hibernate ,可以将 hibernate.globally_quoted_identifiers 属性设置为 true

spring.jpa.properties.hibernate.globally_quoted_identifiers=true

顾名思义,hibernate 会自动对所有数据库标识符添加双引号。

因此,在使用 @Table@Column 注解时,我们无需手动转义表或列名。

简而言之,以下是一些需要考虑的重要关键点:

  • 确保使用正确的 SQL 关键字,并确保其使用顺序。
  • 避免使用保留关键字作为标识符。
  • 仔细检查 SQL 中不允许使用的任何特殊字符。
  • 确保正确转义或用引号包裹任何保留关键字。

5、总结 {#5总结}

本文详细解释了 org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement expected "identifier" 异常背后的原因。然后,我们展示了如何复现此异常以及如何修复。


参考:https://www.baeldung.com/spring-boot-h2-jdbcsqlsyntaxerrorexception-expected-identifier

赞(2)
未经允许不得转载:工具盒子 » 在 Spring Boot 中使用 H2 异常:JdbcSQLSyntaxErrorException