5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

H2Database テーブルが見つからないエラー (Spring boot)

Last updated at Posted at 2021-02-14

##環境
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のカテゴリ別重要プロパティ一覧

5
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?