Spring Data JDBCの使い方 – 【Java】

Spring Data JDBCの使い方 – 【Java】

前提

項目
プロジェクト Gradleプロジェクト
Spring Boot 3.1.3
Language 17

Spring Data JDBCがサポートしているDBです。

  • DB2
  • H2
  • HSQLDB
  • MariaDB
  • Microsoft SQL Server
  • MySQL
  • Oracle
  • Postgres

build.gradle

build.gradleで1行追加します。

implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'

CrudRepository

org.springframework.data.repository.CrudRepositoryをimplementしたインタフェースを定義します。

findAll()やfindById()、save()やcount()など基本的なCRUDのメソッドが用意されています。

saveAll(),findAll(),findAllById()がIterableを返します。

ListCrudRepository ※ver3以降

org.springframework.data.repository.ListCrudRepositoryをimplementしたインタフェースを定義します。

findAll()やfindById()など基本的なCRUDのメソッドが用意されています。

saveAll(),findAll(),findAllById()がListを返します。

PagingAndSortingRepository

ページングをしたい場合はorg.springframework.data.repository.PagingAndSortingRepositoryをimplementしたインタフェースを定義します。

findAll()で全検索します。

PagingAndSortingRepository<Employee, Long> repository;
Page<Employee> employee = repository.findAll(PageRequest.of(1, 20));

引数にorg.springframework.data.domain.PageRequestを指定してページングします。

PageRequest.of(ページ数,ページサイズ);
引数
第一引数 ページ数(0基底)
第二引数 ページサイズ

@Query

@Queryアノテーション(org.springframework.data.jdbc.repository.query.Query)を使用してnative queryを使用します。

@Query("SELECT * FROM EMPLOYEE WHERE NAME = :name")
List xxx(@Param("name") String name);

Springはorg.springframework.data.repository.query.Paramを省略しても良いようです。

Spring fully supports Java 8’s parameter name discovery based on the -parameters compiler flag. By using this flag in your build as an alternative to debug information, you can omit the @Param annotation for named parameters.

メソッド名からSQLを生成する ※Selectのみ

JPAだとfindByXXXのようにメソッド名からSQLを生成する機能があります。

同様の機能がSpring Data JDBCでもありますが、Select文だけサポートされているようです。

Deriving a query from the name of the method is is currently limited to simple properties, that means properties present in the aggregate root directly. Also, only select queries are supported by this approach.

save()メソッド

save()メソッドでインサートとアップデートを行います。@Idを付与したPKがnullの場合、インサートし、設定している場合、その値のデータをアップデートします。

テーブル側のDDLでPKはauto incrementされている必要があります。

ナチュラルキーにしたい場合はPersistableインタフェースをimplementしてisNew()メソッドをオーバーライドして判断する必要があります。

save()メソッド ※Persistable

エンティティにorg.springframework.data.domain.Persistableをimplementsさせて2つのメソッドをオーバーライドします。

  • getId()
  • isNew()

isNew()メソッドでsave()がインサートかアップデートかをコントロールします。

@Table("USER")
@Getter
@AllArgsConstructor
public class XxxEntity implements Persistable {

    @PersistenceCreator
    public XxxEntity(Long id, String name, Integer age) {
        this.id = id;
        this.name= name;
        this.age= age;
    }

    @Id
    @Column("ID")
    Long id;

    @Column("NAME")
    String name;

    @Column("AGE")
    Integer age;

    @Transient
    boolean isNew;

    @Override
    @Nullable
    public Long getId() {
        return id;
    }

    @Override
    public boolean isNew() {
        return isNew;
    }
}

isNewフィールドには@Transientアノテーションを付与することにより永続化対象外のフィールドにします。

コンストラクタに@PersistenceCreatorアノテーションを付与することにより、Spring Data JDBCに使用させるコンストラクタを指定します。※@PersistenceConstructorアノテーションは非推奨

データ生成は@AllArgsConstructorで自動生成したコンストラクタを使用し、isNewにtrue or falseを渡してインサート or アップデートをコントロールします。

XxxEntity entity = new XxxEntity(1L, "tani", 20, true); // trueなのでinsert
repo.save(entity); // insertされる
XxxEntity entity = new XxxEntity(1L, "tani", 20, false); // falseなのでupdate
repo.save(entity); // updateされる

isNew()メソッドを使う場合はPKはauto incrementされている必要がありません。

SQLログ

SQLログをコンソール出力する場合は、application.ymlに以下追記します。

logging:
  level:
    org:
      springframework:
        jdbc: 
          core: 
            JdbcTemplate: TRACE

1対1のEntity

1対1のテーブルをEntityで表します。

H2のDDLです。

CREATE TABLE PARENT(
  id INTEGER AUTO_INCREMENT PRIMARY KEY,
  parent_name TEXT NOT NULL
);

CREATE TABLE CHILD(
  id INTEGER AUTO_INCREMENT PRIMARY KEY,
  child_name TEXT NOT NULL,
  parent_id INTEGER NOT NULL,
  FOREIGN KEY (parent_id) REFERENCES PARENT(id)
);

この親子テーブルをエンティティで表します。

Parentテーブルです。

package jp.co.confrage.demo.domain.entity;

import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Column;
import lombok.AllArgsConstructor;
import lombok.Data;

@AllArgsConstructor
@Data
public class Parent {
  @Id Long id;
  String parentName;
  @Column("PARENT_ID") Child child;
}

Childテーブルです。PKやFKの定義は不要です。

package jp.co.confrage.demo.domain.entity;
import lombok.AllArgsConstructor;
import lombok.Data;

@AllArgsConstructor
@Data
public class Child {
  String childName;
}

Parentのリポジトリインタフェースです。

package jp.co.confrage.demo.infrastructure.repository;

import org.springframework.data.repository.ListCrudRepository;
import jp.co.confrage.demo.domain.entity.Parent;

public interface ParentRepository extends ListCrudRepository<Parent, Long> {
}

コントローラを作成してsaveメソッドでインサートします。

package jp.co.confrage.demo.presentation.controller;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import jp.co.confrage.demo.domain.entity.Child;
import jp.co.confrage.demo.domain.entity.Parent;
import jp.co.confrage.demo.infrastructure.repository.ParentRepository;
import lombok.RequiredArgsConstructor;
@RestController
@RequiredArgsConstructor
public class DemoController {

    private final ParentRepository repo;

    @RequestMapping(path = "/test", method = RequestMethod.GET)
    public ResponseEntity<?> read(@RequestHeader HttpHeaders headers) throws Exception {

        Child child = new Child("takahashi");
        Parent parent = new Parent(null, "yamada", child);
        repo.save(parent);

        return new ResponseEntity<>(null, headers, HttpStatus.OK);
    }
}

Parentテーブル、Childテーブルに1レコードずつインサートされます。

監査ログ

登録者、登録日、更新者、更新日をアノテーションを使用してinsert/update時に自動で設定することができます。

以下のクラスを作成します。

package jp.co.confrage.demo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.data.jdbc.repository.config.EnableJdbcAuditing;

@EnableJdbcAuditing()
@Configuration
public class AuditLogConfig {}

DDLに登録日、更新日を追加します。

CREATE TABLE PARENT(
  id INTEGER AUTO_INCREMENT PRIMARY KEY,
  parent_name TEXT NOT NULL,
  created_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE CHILD(
  id INTEGER AUTO_INCREMENT PRIMARY KEY,
  child_name TEXT NOT NULL,
  parent_id INTEGER NOT NULL,
  created_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY (parent_id) REFERENCES PARENT(id)
);

エンティティに日付を追加します。

Parentテーブルです。

package jp.co.confrage.demo.domain.entity;

import java.time.LocalDateTime;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.relational.core.mapping.Column;
import lombok.AllArgsConstructor;
import lombok.Data;

@AllArgsConstructor
@Data
public class Parent {
  @Id Long id;
  String parentName;
  @Column("PARENT_ID") Child child;
  @CreatedDate LocalDateTime createdDate;
  @LastModifiedDate LocalDateTime updatedDate;
}

Childテーブルです。

package jp.co.confrage.demo.domain.entity;

import java.time.LocalDateTime;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import lombok.AllArgsConstructor;
import lombok.Data;

@AllArgsConstructor
@Data
public class Child {
  String childName;
  @CreatedDate LocalDateTime createdDate;
  @LastModifiedDate LocalDateTime updatedDate;
}

コントローラでsave()メソッドで登録・更新します。登録日、更新日はnull設定すれば自動で設定してくれます。

  Child child = new Child("takahashi", null, null);
  Parent parent = new Parent(null, child, "yamada", null, null);
  repo.save(parent);

参考サイト

Spring Data JDBC
Level up your Java code and explore what Spring can do for you.
Spring Data JDBC - Reference Documentation
Overview (Spring Data Relational Parent 3.1.3 API)
package index
Spring Boot JDBC Template SQL Log
I am trying log SQL queries with params for Spring Boot JDBC but it is not printing the details in log.I am using Spring...

コメント

タイトルとURLをコピーしました