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

##環境
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の設定をしていた。

####ファイル


エントリポイント

```Java 
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

```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](https://www.amazon.co.jp/%E3%81%AF%E3%81%98%E3%82%81%E3%81%A6%E3%81%AESpring-Boot%E2%80%95%E3%80%8CSpring-Framework%E3%80%8D%E3%81%A7%E7%B0%A1%E5%8D%98Java%E3%82%A2%E3%83%97%E3%83%AA%E9%96%8B%E7%99%BA-I%E3%83%BB-BOOKS/dp/4777518655)
[SpringBootのDB初期化方法](https://qiita.com/thankkingdom/items/f2620c7a13450de50d5d)
[Spring Boot 2.0のカテゴリ別重要プロパティ一覧](https://qiita.com/suke_masa/items/d783528eb05ccbaded78)