(第7回) schema.sqlを使用してDBのテーブル作成【H2, Spring Boot2】

H2入門の第7回です。DDLのschema.sqlファイルを作成し、Spring Bootアプリ起動時にDBのテーブル生成をするための設定を説明しています。Spring Bootの初心者・入門者の方は、参考にしてみてください。

環境と今回の目的

最終更新日:2022/11/27

以前にSpring Bootアプリの起動時に、Spring Data JPAの機能でエンティティクラスからDBのテーブルを自動生成し、その動作結果をH2 Consoleで確認しました。

(第2回) H2の接続設定、エンティティクラスの作成、data.sqlで初期データ作成【Spring Boot2】
(第3回) H2のブラウザ管理ツール"H2 Console"の使い方【H2, Spring Boot2】

今度は、エンティティクラスからテーブル生成をするのではなく、schema.sqlファイルにDDL(Data Definition Language)を自分で書いて準備してテーブル生成をしてみたいと思います。

・開発環境やバージョンは以下の通りです。
OS:macOS Big Sur(バージョン11.7.1)
開発環境:Eclipse(Pleiades All in One、4.16(2020-06)、Java Full Edition版)
Spring Boot:バージョン2.7.6
Java:11
データベース:H2

DDLのschema.sqlを作成しテーブル生成する。spring.jpa.hibernate.ddl-autoの設定

まず、プロジェクトのsrc/main/resourcesディレクトリ下にschema.sqlファイルを作成して編集します。
(*schema.sqlに書くsqlをコメントアウトしたい場合、行頭に"--"を付けます)

create table diary (id integer generated by default as identity, comment varchar(255), create_datetime timestamp not null, primary key (id));
schema.sqlの内容は、diaryテーブルを作成するだけのDDLです。エンティティクラスDiaryから生成されるテーブルと同じテーブル構成です。

Spring Bootでは、src/main/resourcesディレクトリ下にschema.sql(DDL)とdata.sql(DML)という名前のファイルがあると、そのファイル内に書いてあるsqlをアプリ起動時に自動で実行してくれます。

この段階でアプリを起動すると、起動時にエラーが発生します。

2022-11-26 20:18:36.966 ERROR 41000 --- [  restartedMain] jdbc.sqlonly                             : 1. Statement.execute(create table diary (id integer generated by default as identity, comment varchar(255), create_datetime timestamp not null, primary key (id))) create table diary (id integer generated by default as identity, comment varchar(255), create_datetime 
timestamp not null, primary key (id)) 
org.h2.jdbc.JdbcSQLSyntaxErrorException: テーブル "DIARY" はすでに存在します
Table "DIARY" already exists; SQL statement:
〜
この起動時エラーは、Spring Data JPAの機能でDiaryエンティティクラスがdiaryテーブルを自動生成した後に、今回のschema.sqlファイルが同じdiaryテーブルを作成しようとして、diaryテーブルはすでに存在するというエラーが発生しています。

ですので、ここではアプリ起動時にSpring Data JPAによってテーブルを自動生成する機能を無効にします。そのために、application.propertiesに"spring.jpa.hibernate.ddl-auto"プロパティの設定を追加します。

spring.jpa.hibernate.ddl-auto=none

ちなみに"spring.jpa.hibernate.ddl-auto"プロパティに設定できる値は、none,validate,update,create,create-dropです。詳しくはSpring Bootのリファレンスドキュメントを参考にしてください。
9. データベースの初期化 / Spring Boot 「使い方」ガイド - リファレンスドキュメント

Spring Data JPAの機能を無効化したので、DBのテーブル作成とデータ初期化処理をschema.sqlとdata.sqlそれぞれで行うようになります。(*schema.sqlはDDL(Data Definition Language、テーブル定義)で、data.sqlはDML(Data Manipulation Language、初期データ作成)です)

これで再度アプリを起動して、起動ログを確認してみます。

〜
2022-11-26 20:35:24.032  INFO 42326 --- [  restartedMain] jdbc.sqlonly                             : create table diary (id integer generated by default as identity, comment varchar(255), create_datetime 
timestamp not null, primary key (id)) 
2022-11-26 20:35:24.046  INFO 42326 --- [  restartedMain] jdbc.sqlonly                             : INSERT INTO diary(comment, create_datetime) VALUES('今日は晴れ。コメント1', LOCALTIME()) 
2022-11-26 20:35:24.053  INFO 42326 --- [  restartedMain] jdbc.sqlonly                             : INSERT INTO diary(comment, create_datetime) VALUES('comment 2', LOCALTIME()) 
2022-11-26 20:35:24.054  INFO 42326 --- [  restartedMain] jdbc.sqlonly                             : INSERT INTO diary(comment, create_datetime) VALUES('こめんと3', LOCALTIME()) 
2022-11-26 20:35:24.098  INFO 42326 --- [  restartedMain] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2022-11-26 20:35:24.153  INFO 42326 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2022-11-26 20:35:24.166  INFO 42326 --- [  restartedMain] com.example.demo.TestH2Application       : Started TestH2Application in 3.42 seconds (JVM running for 4.434)
2022-11-26 20:35:24.298  INFO 42326 --- [  restartedMain] jdbc.sqlonly                             : select diary0_.id as id1_0_, diary0_.comment as comment2_0_, diary0_.create_datetime as create_d3_0_ 
from diary diary0_ 
2022-11-26 20:35:24.316  INFO 42326 --- [  restartedMain] jdbc.resultsettable                      : 
|---|------------|----------------------|
|id |comment     |create_datetime       |
|---|------------|----------------------|
|1  |今日は晴れ。コメント1 |2022-11-26 20:35:24.0 |
|2  |comment 2   |2022-11-26 20:35:24.0 |
|3  |こめんと3       |2022-11-26 20:35:24.0 |
|---|------------|----------------------|
〜
SQLログを見ると、今度はcreate SQL、insert SQLが実行されてテーブルとデータの初期化がされた後に、全件取得のselect SQLが実行されて結果も出力されました。これは期待した結果です。

SQLログの出力は、Log4jdbc-log4j2を使用しています。Log4jdbc-log4j2でのSQLロギングの設定は別ページで説明していますので、そちらを参考にしてください。
H2の管理ツール"H2 Console"、Log4jdbc-log4j2用のドライバDriverSpy使用時【Spring Boot2】

Spring Boot 本をAmazonで探す [広告]

data.sqlとschema.sqlのファイルパスをapplication.propertiesで明示する

data.sql(DML、データ初期化)とschema.sql(DDL、テーブル生成)の2つのファイルは、Spring Bootプロジェクトのsrc/main/resourcesディレクトリ下に作成しておけば、自動でファイルをロードしてファイル内のSQLを実行してくれます。

ただ、この2つのファイルパスを自分で指定する事もでき、application.propertiesで「spring.sql.init.*」プロパティを設定すればできます。

spring.sql.init.schema-locations=classpath:schema.sql
spring.sql.init.data-locations=classpath:data.sql
基本的には、デフォルトのファイスパスを使って、分かりやすいようにファイルパスを明示しておくのも良いかなと思います。

最後に、次回

今回は、Spring BootアプリのDBのテーブル生成をschema.sqlからやる設定をしました。テーブル生成をエンティティクラスで行うか、schema.sqlで行うかの選択は、個人やプロジェクトによると思います。(そもそもDB設計でテーブルを用意しておく事の方が多いと思いますが。)

また、DDLをschema.sqlなどのファイルで管理する場合ですが、FlywayというオープンソースのDBマイグレーションツールがありますので、それを利用するのも便利です。
アプリで使うDBのテーブル構成はどんどん変化していきますから、Flywayを使うとDDLファイルの簡単なバージョン管理が行えます。

次回ですが、今まではH2データベースはインメモリで使ってきましたが、データの保存先をファイルにしてみたいと思います。保存先をファイルにする事でDBのデータが永続化されるので、Spring Bootアプリを何度起動し直してもデータは残ります。

(第8回) H2のデータ保存先をファイルに設定、データの永続化【Spring Boot2】
H2データベース入門【Spring Boot】トップに戻る