0
0

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.

Spring × Gradleにおいて[jpa-schema-gradle-plugin]プラグインを用いてDDLを自動生成する

Last updated at Posted at 2020-12-27

概要・背景

SpringBootのJavaアプリにおいて、application.propertiesにspring.jpa.hibernate.ddl-auto=create-dropとかDDLに関する設定値を定義すればテーブルを自動生成してくれるけど、
「毎回dropされてデータが初期化されてしまう」とか「移行用とかなんだかんだでDDL必要だよね」っていうシーンでは融通が利かないので、DDLを自動生成するgradleタスクを作成した。

良さげなプラグインjpa-schema-gradle-pluginが公開されていたのでこれを利用する。
このプラグインは指定パッケージ配下(packageToScanの設定値)の中でEntityクラスのものを読み込んでDDLを作成してくれる。

前提条件

Spring Boot
gradle
(build.gradleの使い方とかは理解しているものとする。)

準備

1. プラグイン呼び出しのアプリ設定

jpa-schema-gradle-pluginのHow to Useに従い、必要な設定値を定義していく。
今回自分はDBはOracle、OR mapperはHibernateなので、最終的な最終的な設定値は以下のようになった。

build.gradle

plugins {
  id 'io.github.divinespear.jpa-schema-generate' version '0.3.6'
}
dependencies {
  implementation 'com.oracle.database.jdbc:ojdbc8:19.8.0.0'
}
generateSchema {
    vendor = 'hibernate'
    packageToScan = ['com.example.domain']   //自身のgradleプロジェクト または domainのディレクトリを直指定する。
    databaseProductName = 'Oracle12'
    scriptAction = 'drop-and-create'   //drop.sqlとcreate.sqlが作成される。
    properties = [
            'hibernate.dialect': 'org.hibernate.dialect.Oracle12cDialect',
            'hibernate.physical_naming_strategy': 'org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy',    //column nameで"_"が入るようにする。
            'hibernate.implicit_naming_strategy': 'org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy'
    ]
}

2.Entityの用意
Entityは以下の用にsrc/main/java/com/example/domain/にCustomer.javaとSpringUser.javaを用意した。

Customer.java
package com.example.domain;

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

import javax.persistence.*;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "CUSTOMER")
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_CUSTOMER_GENERATOR")
    @SequenceGenerator(name = "SEQ_CUSTOMER_GENERATOR", sequenceName = "SEQ_CUSTOMER", allocationSize = 1)
    private Integer id;
    @Column
    private String firstName;
    @Column
    private String lastName;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(nullable = true, name = "USER_NAME")
    private SpringUser user;

}
SpringUser.java
package com.example.domain;

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.*;

import javax.persistence.*;
import java.util.List;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "SPRING_USER")
@ToString(exclude = "customers")    //これはフィールド変数のcustomers
public class SpringUser {
    @Id
    private String userName;
    @JsonIgnore
    private String encodedPassword;
    @JsonIgnore
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "user")
    private List<Customer> customers;
}

実行

上述のbuild.gradleを作ったら、"Refresh all Gradle Projects"を忘れずに実行する(gradleタスクが追加される)。
ターミナルからgradle generateSchemaと実行してやれば、build/generated-schema/create.sqlが作成される(デフォルトの出力先)。

出来上がったcreate.sqlがこちら。
Customer.javaで定義した通り、SEQUENCEもきちんと反映して作成されている。
カラムの物理名に"_"をいれるかどうかなどは、build.gradleで設定した値"SpringPhysicalNamingStrategy"で変更したりできるので、細かい仕様は、jpa-schema-gradle-pluginのHow to Useを読めばいいと思います。

create.sql
create sequence seq_customer start with 1 increment by  1;
create table customer (id number(10,0) not null, first_name varchar2(255 char), last_name varchar2(255 char), user_name varchar2(255 char), primary key (id));
create table spring_user (user_name varchar2(255 char) not null, encoded_password varchar2(255 char), primary key (user_name));
alter table customer add constraint FKc7gvbu1i8l83wyt8q39egdfka foreign key (user_name) references spring_user;

陥ったトラブル

トラブル1: KotlinNullPointerException
jpa-schema-gradle-pluginのHow to Useを見ると、
persistence.xmlを使用しない場合の最低限の設定値は、
vendor = 'hibernate'
packageToScan = ['com.example.domain']
だけのように見えるがこれだと、generateSchemaを実行したときにKotlinNullPointerExceptionが発生する。
⇒解決方法: databaseProductNameを設定する必要がある。

トラブル2: gradleタスクにgenerateSchemaは登録されるが、実行してもcreate.sqlが作成されない
イージーミスでした。scriptAction = 'drop-and-create'が抜けているだけでした。

まとめ

DDLを自動生成することで、プロジェクト参画メンバーの環境構築を円滑に行うことができるため、このプラグインの導入はおすすめです。
まぁ最近ではflywayとか使ってDDLの自動生成や移行の簡略化とかも簡単にできますが、一度自分でプラグインを作ってみたり、追うことで新しい技術を取り込むときのハードルを下げることができると思っています。

ここまで読んでいただきありがとうございました。:bow:

0
0
0

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?