修復 Spring Boot H2 異常:“未找到架構”
1. 概述
H2 是一個開源 SQL 資料庫,通常在 Java 社群中用於測試目的。它的記憶體特性不會將任何內容保留到磁碟上,這使得它非常快。
當我們與Spring Boot整合時,可能會遇到「 Schema not found 」的錯誤訊息。在本教程中,我們將探討其原因並研究兩種不同的方法來解決它。
2. 了解原因
H2 的預設模式是PUBLIC 。如果我們映射不使用PUBLIC模式的 JPA 實體類,我們必須確保該模式是在 H2 上建立的。當目標 schema 不存在時,Spring Boot 會報告錯誤訊息「 Schema not found 」。
為了模擬該場景,我們在 Spring Boot 應用程式中建立以下實體類別和儲存庫。 @Table註釋指定實體對應到test模式中的學生表的表映射詳細資訊:
@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;
// constructor, getters and setters
}
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 應用程式啟動時建立對應的 schema。有兩種不同的方法可以做到這一點。
第一種方法是在建立資料庫連線時建立資料庫模式。當客戶端透過INIT屬性連接到資料庫時,H2 資料庫 URL 允許我們執行 DDL 或 DML 命令。在 Spring Boot 應用程式中,我們可以在application.yaml中定義spring.datasource.url屬性:
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 建立架構,無需明確建立表格。我們透過在 YAML 檔案中設定屬性spring.jpa.hibernate.ddl-auto來create依賴 Hibernate 中的自動模式建立。
4. 透過初始化腳本建立模式
第二種方法是通用的,也可以應用於其他資料庫。我們透過初始化腳本來建立所有資料庫元件,包括架構和表格。
Spring Boot 在執行初始化腳本之前初始化 JPA 持久單元。因此,我們在application.yaml中明確停用 Hibernate 的自動模式生成,因為我們的初始化腳本會處理它:
spring:
jpa:
hibernate:
ddl-auto: none
如果我們不停用它,我們在應用程式啟動過程中會遇到「 Schema TEST not found 」的異常。在 JPA 持久性單元初始化期間尚未建立架構。
現在,我們可以將建立test模式和student表的schema.sql放在resources資料夾中:
CREATE SCHEMA IF NOT EXISTS test;
CREATE TABLE test.student (
student_id VARCHAR(10) PRIMARY KEY,
name VARCHAR(100)
);
Spring Boot預設在應用程式啟動時會尋找resources資料夾中的DDL腳本chema.sql來初始化資料庫。
5. 結論
「 Schema not found 」異常是 Spring Boot 應用程式啟動與 H2 資料庫整合期間的常見問題。我們可以透過確保透過資料庫 URL 配置或初始化腳本建立模式來避免這些異常。
與往常一樣,程式碼範例可在 GitHub 上取得。