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-auto
从create
改为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时的常见踩坑点。通过以下两种方式可避免异常:
- ✅ 数据库URL配置(H2专用)
- ✅ 初始化脚本(通用方案)
完整代码示例已托管至GitHub仓库