1. 概述

H2是Java社区常用的开源SQL数据库,特别适合测试场景。它的内存特性不会持久化任何数据到磁盘,因此速度极快。

在Spring Boot集成H2时,我们可能会遇到“Schema not found”错误。本文将深入分析该异常的成因,并提供两种解决方案。

2. 问题根源解析

⚠️ H2的默认模式是PUBLIC。如果JPA实体类映射到非PUBLIC模式,必须确保该模式已在H2中创建。当目标模式不存在时,Spring Boot就会抛出“Schema not found”异常。

先复现问题场景,创建以下实体类和仓库:

@Entity
@Table(name = "student", schema = "test")
public class Student {
    @Id
    @Column(name = "student_id", length = 10)
    private String studentId;

    @Column(name = "name", length = 100)
    private String name;

    // 构造方法、getter和setter
}
public interface StudentRepository extends JpaRepository<Student, String> {
}

启动Spring Boot应用并访问仓库,会抛出异常。通过集成测试验证:

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = SampleSchemaApplication.class)
class SampleSchemaApplicationIntegrationTest {
    @Autowired
    private StudentRepository studentRepository;

    @Test
    void whenSaveStudent_thenThrowsException() {
        Student student = Student.builder()
          .studentId("24567433")
          .name("David Lloyds")
          .build();

        assertThatThrownBy(() -> studentRepository.save(student))
          .isInstanceOf(InvalidDataAccessResourceUsageException.class);
    }
}

控制台将输出如下错误:

org.hibernate.exception.SQLGrammarException: could not prepare statement [Schema "TEST" not found; SQL statement:
select s1_0.student_id,s1_0.name from test.student s1_0 where s1_0.student_id=? [90079-214]] [select s1_0.student_id,s1_0.name from test.student s1_0 where s1_0.student_id=?]

3. 通过数据库URL创建模式

解决该问题的关键在于:Spring Boot启动时必须创建目标模式。这里提供两种实现方式。

第一种方案是在建立数据库连接时创建模式。H2数据库URL支持通过INIT属性执行DDL/DML命令。在application.yaml中配置:

spring:
  jpa:
    hibernate:
      ddl-auto: create
  datasource:
    driverClassName: org.h2.Driver
    url: jdbc:h2:mem:test;INIT=CREATE SCHEMA IF NOT EXISTS test

初始化DDL会检查并创建模式。✅ 注意:

  • 这是H2特有的方案,其他数据库可能不兼容
  • 通过数据库URL创建模式后,仍需依赖Hibernate的ddl-auto: create自动建表

4. 通过初始化脚本创建模式

第二种方案是通用方案,适用于多种数据库。我们通过初始化脚本创建完整的数据库结构(包括模式和表)。

⚠️ Spring Boot会在执行初始化脚本前初始化JPA持久化单元。因此需要在application.yaml中禁用Hibernate的自动建表功能:

spring:
  jpa:
    hibernate:
      ddl-auto: none

若不将ddl-autocreate改为none,启动时仍会抛出“Schema TEST not found”异常——因为JPA初始化时模式尚未创建。

resources目录下创建schema.sql脚本:

CREATE SCHEMA IF NOT EXISTS test;

CREATE TABLE test.student (
  student_id VARCHAR(10) PRIMARY KEY,
  name VARCHAR(100)
);

Spring Boot默认会在启动时加载resources目录下的schema.sql文件初始化数据库

5. 总结

“Schema not found”是Spring Boot集成H2时的常见踩坑点。通过以下两种方式可避免异常:

  1. ✅ 数据库URL配置(H2专用)
  2. ✅ 初始化脚本(通用方案)

完整代码示例已托管至GitHub仓库


原始标题:Fixing Spring Boot H2 Exception: “Schema not found” | Baeldung