解决 Spring Boot H2 JdbcSQLSyntaxErrorException “Table not found”

1、简介

H2 是一个简单的轻量级内存数据库,Spring Boot 可以自动对其进行配置,使开发人员可以轻松测试数据访问逻辑。

通常情况下,org.h2.jdbc.JdbcSQLSyntaxErrorException 是用于表示与 SQL 语法相关的错误的异常。“Table not found” 表示 H2 无法找到指定的表。

本文将带你了解 H2 抛出 JdbcSQLSyntaxErrorException 异常的原因以及解决办法。

2、示例

既然知道了异常背后的根本原因,来看看如何重现异常。

2.1、H2 配置

Spring Boot 会配置应用使用用户名 sa 和空密码连接到可嵌入的数据库 H2。将这些属性添加到 application.properties 文件中:

spring.datasource.url=jdbc:h2:mem:mydb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

现在,假设有一个名为 person 的表。在此,使用一个基本的 SQL 脚本为数据库添加数据。默认情况下,Spring Boot 会加载 data.sql 文件:

INSERT INTO "person" VALUES (1, 'Abderrahim', 'Azhrioun');
INSERT INTO "person" VALUES (2, 'David', 'Smith');
INSERT INTO "person" VALUES (3, 'Jean', 'Anderson');

2.2、对象关系映射

接下来,使用 JPA 注解将表 person 映射到一个实体。

Person 实体如下:

@Entity
public class Person {

    @Id
    private int id;
    @Column
    private String firstName;
    @Column
    private String lastName;

    // Getter/Setter 方法省略

}

@Entity 注解表明该类是一个映射 person 表的实体。此外,@Id 表示 id 属性代表主键,@Column 注解将表列绑定到实体字段。

接下来,为实体 Person 创建一个 JPA Repository:

@Repository
public interface PersonRepository extends JpaRepository<Person, Integer> {
}

Spring Data JPA 提供了 JpaRepository 接口,以简化存储和检索数据的逻辑。

现在,尝试启动 Spring Boot 应用,看看会发生什么。查看日志,可以发现应用在启动时出现了 org.h2.jdbc.JdbcSQLSyntaxErrorException: Table “person” not found 异常:

Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
...
at com.baeldung.h2.tablenotfound.TableNotFoundExceptionApplication.main(TableNotFoundExceptionApplication.java:10)
...
Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "person" not found (this database is empty); SQL statement:
...

这里出错的原因是,data.sql 脚本是在 Hibernate 初始化之前执行的。这就是为什么 Hibernate 找不到表 person 的原因。

通常,这是为了将基于脚本的初始化行为与其他数据库迁移工具(如 LiquibaseFlyway)保持一致而设定的默认行为。

3、解决办法

幸运的是,Spring Boot 提供了解决这一限制的快捷方法。只需在 application.properties 中将 spring.jpa.defer-datasource-initialization 属性设置为 true,即可避免异常:

spring.jpa.defer-datasource-initialization=true

如上,覆盖默认行为,在 Hibernate 初始化后推迟数据初始化。

最后,添加一个测试用例验证是否正常:

@SpringBootTest(classes = TableNotFoundExceptionApplication.class)
class TableNotFoundExceptionIntegrationTest {

    @Autowired
    private PersonRepository personRepository;

    @Test
    void givenValidInitData_whenCallingFindAll_thenReturnData() {
        assertEquals(3, personRepository.findAll().size());
    }
}

不出所料,测试成功通过。

4、总结

本文介绍了了导致 H2 抛出 “JdbcSQLSyntaxErrorException: Table not found” 的原因以及解决办法。


Ref:https://www.baeldung.com/spring-boot-h2-jdbcsqlsyntaxerrorexception-table-not-found