Spring Data JDBCの使い方 – 【Java】

Spring Data JDBCの使い方 – 【Java】

前提

項目
プロジェクトGradleプロジェクト
Spring Boot3.1.3
Language17

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.

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 UNIQUE,
  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;

public record Parent(@Id Long id, String parentName, @Column("PARENT_ID") Child child) {
}

Childテーブルです。PKやFKの定義は不要です。定義した場合は、PK,FKともにnullを設定すれば動作はします。

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

public record 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レコードずつインサートされます。

参考サイト

Spring Data JDBC
LevelupyourJavacodeandexplorewhatSpringcandoforyou.
Spring Data JDBC - Reference Documentation
Overview (Spring Data Relational Parent 3.1.3 API)
packageindex
Spring Boot JDBC Template SQL Log
IamtryinglogSQLquerieswithparamsforSpringBootJDBCbutitisnotprintingthedetailsinlog.IamusingSpringBoot1.5.8version.Pleasehelpmetosolvethis.application.properties...

コメント

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