2021-04-05 中田 JPAの説明とJpaRepository等の説明を加筆
2020-05-19 中村
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操作に付随する手間も大きく削減できる.
これを使わない手はない!
健康診断システム(ソフトウェア工学第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を使う.
//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'
$ mysql -u root -p パスワード入力 mysql> CREATE DATABASE medicalcheck; mysql> CREATE USER newse IDENTIFIED BY 'newse'; mysql> GRANT ALL ON medicalcheck.* TO newse;
# 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クラスを下記のようにアノテーションする.
@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 }
JPAが用意している CrudRepositoryを継承する形でPersonRepositoryを作成する.
PersonRepository.java
@Repository public interface PersonRepository extends CrudRepository<Person, Long> { }
デフォルトで以下のクラスが自動生成される.
自動生成されるメソッドの説明は以下の通り.
Person p = persons.findById(number).orElseThrow( ()-> new NoSuchPersonException(number + ": No such person exists Person ") );
PersonRepositoryで「もう少し凝った」データの問い合わせ(クエリ)を行いたいという要求を考えよう. 例えば以下のような感じ.
これらの要求に対し,とりあえず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を書くやり方がある.
PersonRepositoryに以下を追加してみる.
/** 生まれ月で検索 */ @Query(value = "SELECT * FROM person p where MONTH(p.birthday) = ?1", nativeQuery = true) public Iterable<Person> findPersonByBirthMonth(int month);
JpaRepository -> PagingAndSortingRepository -> CrudRepository -> Repository
の順で継承しているため、利用したい最小機能のRepositoryインタフェースを利用する。
{ "java.configuration.updateBuildConfiguration": "automatic" }