##環境
MacOS Big Sur 11.1
STS 4-4.9.0
Spring Boot 2.4.2
Java 11
H2database 1 .4.200
Maven 4.0.0
##状況
H2DatabaseはJVM環境で動くデータベース。
非常に軽量でJavaのテスト開発では重宝される。
JVM内部にデータベースを設置する埋込型と、指定されたパスにデータベースファイルを設置し保管するローカル型がある。
今回はデータを永続化させるためにローカル型のH2の設定をしていた。
####ファイル
エントリポイント
package com.example.h2test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import com.example.h2test.domain.Customer;
@SpringBootApplication
public class H2testApplication implements CommandLineRunner {
@Autowired
NamedParameterJdbcTemplate jdbcTemplate;
@Override
public void run(String...strings) throws Exception {
String sql = "SELECT id, firstName, lastName from customers where id = :id";
SqlParameterSource param = new MapSqlParameterSource().addValue("id", 1);
Customer result = jdbcTemplate.queryForObject(sql, param, (rs, rowNum)
-> new Customer(rs.getInt("id"), rs.getString("firstName"), rs.getString("lastName")
));
System.out.println("result: " + result);
}
public static void main(String[] args) {
SpringApplication.run(H2testApplication.class, args);
}
}
クラスパス直下にschema.sql
CREATE table IF NOT EXISTS customers (
id int primary key auto_increment,
firstName varchar(30),
lastName varchar(30)
);
application.propertiesファイルにH2データベースを永続化するための設定を記述。
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.url=jdbc:h2:file:./target/db/testdb
spring.datasource.username=sa
spring.datasource.password=
しかし実行後
java.lang.IllegalStateException: Failed to execute CommandLineRunner
Caused by: org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [SELECT id, firstName, lastName from customers where id = ?]; nested exception is org.h2.jdbc.JdbcSQLSyntaxErrorException: テーブル "CUSTOMERS" が見つかりません
Table "CUSTOMERS" not found;
というエラーが発生。
datasource.urlに記述したパスのデータベースファイルを参照する設定。
もしなかった場合はそこにdbファイルを作成するようになっている。
##エラーの原因と解決策
テーブルが見つからない原因は、テーブルがそもそも作成されていないから。
Spring bootはクラスパス直下にschema.sqlというファイルがあれば自動で読み込みテーブルを作成するのだが、どうやら読み込まれていない状況。
原因は、SQLファイルの初期化設定がされていなかったから。
以下のコードをapplication.propertiesファイルに追記する。
spring.datasource.initialization-mode=always
spring.datasource.schema=classpath:schema.sql
#####initialization-mode
schema.sqlなどH2が読み込むsqlファイルをどう初期化するかを指定する。
値は、「always」 「embedded」「never」を選べる。
初期値はembeddedで、これは埋込DB(H2 Database)の時のみ実行という意味。
今回は埋め込み型ではなくローカル型なので、初期設定を「always」にしないとschema.sqlが実行されなかったのだ。
#####schema
どのschemaファイルを読みこむかを指定。
設定しなかった場合クラスパス直下のschema.sqlが読み込まれる。
(今回は省いても良い)
最終的なapplication.propertiesの中身はこうなる。
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.url=jdbc:h2:file:./target/db/testdb
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.initialization-mode=always
spring.datasource.schema=classpath:schema.sql
##まとめ
はじめてのSpring Bootを参考にh2データベースを扱っていました。
ファイルを指定する際初期化について記述されていなかったので、数年前のH2は初期化設定をしなくとも読み込んでくれていたんですかね?
もし間違い等ご指摘があれば、よろしくお願いいたします。
##参考文献
はじめてのSpring Boot
SpringBootのDB初期化方法
Spring Boot 2.0のカテゴリ別重要プロパティ一覧