Spring Boot 2.5でdata.sqlを使ってデータ初期化を行う際の注意点

# 前提
先日、以下を使って簡単なアプリを作ろうとしました。

- Spring Boot 2.5
- JPA
- H2 Database
- data.sql


```java:Item.java
package com.example.domain;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name="items")
public class Item implements Serializable {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer id;
	
	@Column(nullable = false)
	private String name;
	
	@Column(nullable = false)
	private Integer price;
}

```

```sql:data.sql
INSERT INTO items(name, price) VALUES('りんご', 100);
INSERT INTO items(name, price) VALUES('ばなな', 50);
INSERT INTO items(name, price) VALUES('ぶどう', 200);
```

# 起こった事象

Item.javaからJPAで自動生成された「items」というテーブルにただただデータを突っ込んでいくだけのDMLなのですが、以下のエラーが発生しました。

```
Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: テーブル "items" が見つかりません
Table "items" not found; SQL statement:
INSERT INTO items(name, price) VALUES('りんご', 100) [42102-200]
	at org.h2.message.DbException.getJdbcSQLException(DbException.java:453) ~[h2-1.4.200.jar:1.4.200]
	at org.h2.message.DbException.getJdbcSQLException(DbException.java:429) ~[h2-1.4.200.jar:1.4.200]
	at org.h2.message.DbException.get(DbException.java:205) ~[h2-1.4.200.jar:1.4.200]
	at org.h2.message.DbException.get(DbException.java:181) ~[h2-1.4.200.jar:1.4.200]
	at org.h2.command.Parser.readTableOrView(Parser.java:7628) ~[h2-1.4.200.jar:1.4.200]
	at org.h2.command.Parser.readTableOrView(Parser.java:7599) ~[h2-1.4.200.jar:1.4.200]
	at org.h2.command.Parser.parseInsert(Parser.java:1747) ~[h2-1.4.200.jar:1.4.200]
	at org.h2.command.Parser.parsePrepared(Parser.java:954) ~[h2-1.4.200.jar:1.4.200]
	at org.h2.command.Parser.parse(Parser.java:843) ~[h2-1.4.200.jar:1.4.200]
	at org.h2.command.Parser.parse(Parser.java:815) ~[h2-1.4.200.jar:1.4.200]
	at org.h2.command.Parser.prepareCommand(Parser.java:738) ~[h2-1.4.200.jar:1.4.200]
	at org.h2.engine.Session.prepareLocal(Session.java:657) ~[h2-1.4.200.jar:1.4.200]
	at org.h2.engine.Session.prepareCommand(Session.java:595) ~[h2-1.4.200.jar:1.4.200]
	at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1235) ~[h2-1.4.200.jar:1.4.200]
	at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:212) ~[h2-1.4.200.jar:1.4.200]
	at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:201) ~[h2-1.4.200.jar:1.4.200]
	at net.sf.log4jdbc.StatementSpy.execute(StatementSpy.java:839) ~[log4jdbc-remix-0.2.7.jar:na]
	at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) ~[HikariCP-4.0.3.jar:na]
	at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) ~[HikariCP-4.0.3.jar:na]
	at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) ~[spring-jdbc-5.3.10.jar:5.3.10]
	... 28 common frames omitted
```

INSERTするにも、「items」テーブルがないから無理よとのことだったのですが、JPAで自動生成してくれるはずなのに！と途方に暮れていたらどうやらSpring Boot 2.5からdata.sqlが読み込まれるタイミングが変わったようです。

> By default, data.sql scripts are now run before Hibernate is initialized. This aligns the behavior of basic script-based initialization with that of Flyway and Liquibase. If you want to use data.sql to populate a schema created by Hibernate, set spring.jpa.defer-datasource-initialization to true. While mixing database initialization technologies is not recommended, this will also allow you to use a schema.sql script to build upon a Hibernate-created schema before it’s populated via data.sql.

<a href="https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.5-Release-Notes#hibernate-and-datasql">Spring Boot 2.5 Release Notes</a>

リリースノートには「Hibernateの初期化される前にdata.sql実行されるから気をつけや〜！」と書かれております。

# 解決方法

Hibernateの初期化前に実行されるように変更するには、`application.properties`に`spring.jpa.defer-datasource-initialization=true`を追加するといいみたいです。

```properties:application.properties
spring.jpa.defer-datasource-initialization=true
```

よかったよかった〜！