[JAVA] Automatically generate DDL using [jpa-schema-gradle-plugin] plugin in Spring × Gradle

Overview / Background

In SpringBoot Java application, if you define spring.jpa.hibernate.ddl-auto = create-drop or DDL setting value in application.properties, the table will be automatically generated. I created a gradle task that automatically generates DDL because it is inflexible in scenes such as "It is dropped every time and the data is initialized" or "For migration, DDL is necessary for some reason".

A good plugin jpa-schema-gradle-plugin has been released, so I will use it. This plugin reads the Entity class under the specified package (packageToScan setting value) and creates DDL.

Prerequisites

Spring Boot gradle (It is assumed that you understand how to use build.gradle.)

Preparation

__1. App settings for plugin calls __

Define the required setting values ​​according to How to Use of jpa-schema-gradle-plugin. This time, my DB is Oracle and OR mapper is Hibernate, so the final final settings are as follows.

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']   //Directly specify the directory of your own gradle project or domain.
    databaseProductName = 'Oracle12'
    scriptAction = 'drop-and-create'   //drop.sql and create.sql is created.
    properties = [
            'hibernate.dialect': 'org.hibernate.dialect.Oracle12cDialect',
            'hibernate.physical_naming_strategy': 'org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy',    //in column name"_"To enter.
            'hibernate.implicit_naming_strategy': 'org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy'
    ]
}

__2. Preparation of Entity __ Entity prepared Customer.java and SpringUser.java in src/main/java/com/example/domain/for the following.

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")    //This is the field variable 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;
}

Run

After creating the build.gradle above, don't forget to run "Refresh all Gradle Projects" (adding a gradle task). If you run gradle generateSchema from the terminal, build/generated-schema/create.sql will be created (default output destination).

Here is the completed create.sql. As defined in Customer.java, SEQUENCE is also created by reflecting it properly. Whether or not to put "_" in the physical name of the column can be changed with the value "SpringPhysicalNamingStrategy" set in build.gradle, so detailed specifications can be found in jpa-schema-gradle-plugin How I think you should read 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;

Trouble that fell

** Trouble 1: KotlinNullPointerException ** If you look at How to Use of jpa-schema-gradle-plugin, The minimum setting value when persistence.xml is not used is vendor = 'hibernate' packageToScan = ['com.example.domain'] It looks like just this, but when I run generateSchema I get a KotlinNullPointerException. ⇒ Solution: You need to set databaseProductName.

** Trouble 2: generateSchema is registered in gradle task, but create.sql is not created even if it is executed ** It was an easy mistake. I just missed scriptAction ='drop-and-create'.

Summary

By automatically generating DDL, it is possible to smoothly build the environment of the project participating members, so it is recommended to install this plug-in. Well, recently, you can easily generate DDL automatically and simplify migration by using flyway, but you can lower the hurdle when incorporating new technology by creating a plugin by yourself or following it. I think.

Thank you for reading this far. : bow:

Recommended Posts

Automatically generate DDL using [jpa-schema-gradle-plugin] plugin in Spring × Gradle
Automatically generate jpa entity using Gradle
Generate DB documentation using SchemaSpy in Gradle
Spring Boot 2 multi-project in Gradle
Automatically specify version in gradle project
Implement Spring Boot application in Gradle
Automatically deploy a web application developed in Java using Jenkins [Spring Boot application]
Build Spring Boot + Docker image in Gradle
Shortcut to automatically generate javadoc in IntelliJ
Exists using Specification in Spring Data JPA
Resolve "Cannot resolve symbol" in IntelliJ projects using Gradle
Java tips-Create a Spring Boot project in Gradle
[Note] Struts2 environment construction using Gradle in Eclipse
View the Gradle task in the Spring Boot project
How to automatically generate a constructor in Eclipse