SpringBoot

Spring Data JPA を使ったデータ永続化

2021-04-05 中田 JPAの説明とJpaRepository等の説明を加筆

2020-05-19 中村

Spring Data JPAとは

Spring Bootにおいて,データの永続化は@Repositoryが担当する. これをJDBC(Java Database Connectivity)を使ってゴリゴリ自前で 実装してもよいが,多くの場合 Boilerplate Codeが出来上がるだけである.

JPA (Java Persistence API)は, Javaでデータ永続化を効率的に行うAPIをまとめた規格であり,これをSpring の@Repositoryの実装に使えるようにしたものが Spring Data JPA である.

Spring Data JPA を使えば,DBに対する基本的なCRUD操作が全自動で実装 されるので,@Repositoryの実装が爆速(多くの場合コードレス) になる.また,DBのテーブルをEntity Beansに合わせて自動生成 する機能や,値の検査(バリデーション)を行う機能もあるため, DB操作に付随する手間も大きく削減できる.

これを使わない手はない!

JDBC、ORM、JPAとはそもそも何か

例題

健康診断システム(ソフトウェア工学第4回課題)における受診者Personを考える.

@Data
public class Person {
    private Long number;   // 受診番号(ID)
    private String name;   // 受診者名前
    private Date birthday; // 誕生日
    private double height; // 身長 cm
    private double weight; // 体重 kg
}

これをEntityとしてSpring Data JPAで永続化することを考える.DBはMySQLを使う.

準備

  1. build.gradle を編集する.dependenciesの中に以下の依存関係を追加する:
    //Spring JPA
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    //MySQL
    runtimeOnly 'mysql:mysql-connector-java'
    //バリデーション用
    compile 'org.springframework.boot:spring-boot-starter-validation'
    • Ctrl+Shift+P -> Java:Update project configurationで依存関係をupdateすることを忘れない
  2. MySQLに新規DB(例:medicalcheck)を作成する.
    • やり方はデータベース/MySQLあたりを参照のこと.テーブルは作成しなくてよい
    • ユーザ名/パスワードはそのDB用のものを作る.例:newse/newse
    • シェルでやる方法
      $ mysql -u root -p
      パスワード入力
      
      mysql> CREATE DATABASE medicalcheck;
      mysql> CREATE USER newse IDENTIFIED BY 'newse';
      mysql> GRANT ALL ON medicalcheck.* TO newse;
  3. application.propertiesを編集.DBへの接続情報とJPAのDDL設定を追記.
    # MySQLデータベース接続設定
    spring.datasource.url=jdbc:mysql://localhost:3306/medicalcheck?serverTimezone=JST
    spring.datasource.username=newse
    spring.datasource.password=newse
    
    # Spring-JPA: DBのテーブルを自動作成してくれる機能
    # create: 新規作成, update: なければ新規作成, create-drop: 新規作成し終了時に削除
    spring.jpa.hibernate.ddl-auto=update

PersonをJPAのEntityとして設定する

Personクラスを下記のようにアノテーションする.

@Data
@Entity
public class Person {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long number;   // 受診番号(ID)

    private String name;   // 受診者名前

    @Temporal(TemporalType.DATE)
    private Date birthday; // 誕生日

    private double height; // 身長 cm

    private double weight; // 体重 kg

}

PersonRepository の実装

JPAが用意している CrudRepositoryを継承する形でPersonRepositoryを作成する.

公式Doc(Spring Data 2.4.5)

PersonRepository.java

@Repository
public interface PersonRepository extends CrudRepository<Person, Long> {
   
}

PersonRepositry (CrudRepository) の基本メソッド

デフォルトで以下のクラスが自動生成される.

class.png

自動生成されるメソッドの説明は以下の通り.

書き込み系(CREATE, UPDATE)

読み出し系(READ)

削除系 (DELETE)

その他

注意点

カスタムクエリの作成

カスタムクエリの例

PersonRepositoryで「もう少し凝った」データの問い合わせ(クエリ)を行いたいという要求を考えよう. 例えば以下のような感じ.

  1. 名前で受診者を検索したい
  2. 受診者のうち身長が160cm~170cmの人だけを取り出したい
  3. 受診者のうち誕生日が1月の人だけを取り出したい
  4. 受診者のうちBMIが25未満の人の体重を知りたい
  5. 受診者のうち肥満度2の人を見つけたい

これらの要求に対し,とりあえずfindAll()でPersonを全件取り出して,サービス層でデータ分析処理を 行うというやり方も可能だが,めんどくさいしテストも大変である. せっかくDBを使っているのだから,こうした操作はDB側でSQLでやってもらいたいわけである.

このような場合,PersonRepositoryにカスタム・メソッドを追加することで解決できる. ここで紹介するやりかたは以下の2種類.

命名規則に従ったメソッド名による自動実装

上記のPersonRepositoryインタフェースに メソッド・シグニチャ(関数の宣言部)を追加するだけで, JPAが勝手に中身を実装してくれるというもの. 例えばこんな感じ.

PersonRepository.java

@Repository
public interface PersonRepository extends CrudRepository<Person, Long> {

   /** 名前が LIKE name な受診者を返す */
   public Iterable<Person> findPersonByNameLike(String name);
 
   /** 身長がmin~maxの間にある受診者を返す */
   public Iterable<Person> findPersonByHeightBetween(double min, double max);

}

ヤヴァイぐらいシンプルである.どういうカラクリなのか? 実は ある命名規則 に従ってメソッド・シグニチャをつければ,Spring Data JPAが自動実装してくれるのである.

大まかにいうと,

大体のカスタムクエリはこれで用が足りてしまう. より具体的な活用は,この記事などを参照すること.

@QueryにSQLを書いて実装

命名規則のやり方で出来ないような少し複雑なクエリは,@Queryアノテーションをつけて直接SQLを書くやり方がある.

PersonRepositoryに以下を追加してみる.

   /** 生まれ月で検索 */
   @Query(value = "SELECT * FROM person p where MONTH(p.birthday) = ?1",  nativeQuery = true)
   public Iterable<Person> findPersonByBirthMonth(int month);

Spring Data JPAのリポジトリインタフェースの違いについて

JpaRepository -> PagingAndSortingRepository -> CrudRepository -> Repository

の順で継承しているため、利用したい最小機能のRepositoryインタフェースを利用する。

すべてのソースコード

関連を持つエンティティの永続化

参考文献

トラブルシューティング


添付ファイル: fileclass.png 173件 [詳細]

トップ   編集 凍結 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2023-11-23 (木) 23:14:42