前提
先日、以下を使って簡単なアプリを作ろうとしました。
- Spring Boot 2.5
- JPA
- H2 Database
- data.sql
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;
}
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.
リリースノートには「Hibernateの初期化される前にdata.sql実行されるから気をつけや〜!」と書かれております。
解決方法
Hibernateの初期化前に実行されるように変更するには、application.properties
にspring.jpa.defer-datasource-initialization=true
を追加するといいみたいです。
spring.jpa.defer-datasource-initialization=true
よかったよかった〜!