JDBC・Spring JDBC / JPA・Spring Data・Spring Data JPA・Hibernateの関係性

### 導入

今まで業務でなんとなく使っていたSpring JDBC、Spring Data JPAらへんの理解があいまいだったので記事にまとめる。

---
### まず結論

||説明|
|---|---|
|JDBC|JavaでDBに接続するためのAPI。**ResultSetからデータ抜き出すのだるいやつ**。|
|Spring JDBC|JDBCの使いづらいところを取っ払ってくれたもの。**JDBCより断然こっちの方がいい**。**application.propertiesにDB接続情報定義するだけで接続できる**SpringBootの恩恵を受けれるのはありがたい。|
|||
|JPA|Java標準の**ORMの仕様**。JDBC系と異なりSQLを自動生成してくれたり、ORMでデータ取得結果をEntityクラスにぶちこんでくれる。|
|Spring Data|色んなDBを使いやすくする複数のフレームワークの親玉。|
|Spring Data JPA|JPAを使いやすくする抽象クラス/インタフェースを提供してくれる。**これはJPAの実装ではない。**|
|Hibernate|**これがJPAの実装。** Hibernate以外にもあるがほぼほぼHibernateが実装として採用されている印象。|

✅ JavaでORMの恩恵(Entity間の紐付け等)を存分に授かりたいなら「JPA」を使う。さらにJPAを簡単に使いたいなら「Spring Data JPA」を使う。
✅ SQLをできるだけナチュラルな状態で扱いたいなら「Spring JDBC」を使う。Spring JDBCでもORMっぽいことはできるが、Entity間の紐付け(LAZY FETCH等)はできない。


---
### JDBC

・JavaでDBに接続するためのAPI
・ResultSetでデータを受け取り、Beanクラスにデータ格納する手間があるやつ

---
### Spring JDBC

・JDBCをもっといいかんじに使えるようにしたフレームワーク
■ 普通のJDBCとの違い
・**JdbcTemplate**クラスのメソッドを使うだけでデータ登録/更新/検索/削除が可能。
・**RowMapperインターフェース**を使えばBeanクラスへのマッピング処理をいい感じにできる。
・**application.properties**にDB接続情報を定義するだけで接続可能(これはSpringBootの機能である)

```properties
# DB接続情報を定義するだけでOK
spring.datasource.url=
spring.datasource.username=
spring.datasource.password=
spring.datasource.driver-class-name=
spring.datasource.schema=
spring.datasource.data=
```

---
### JPA

・Java標準のORMの**仕様(specification)**
・**実装**(**implementation**)が別で提供されている。**Springはデフォルトで「Hibernate」を実装として利用する**。
https://stackoverflow.com/questions/41902856/spring-boot-jpa-hibernate-as-default

・ORMを実現する仕組みとして「Entity」「EntityManager」の２つの理解が欠かせない。

|||
|----|----|
|Entity|メモリ上のJavaオブジェクト|
|EntityManager|EntityとDBを紐づける仲介者|

> EntityManagerにはPersistence Contextと呼ばれる、Entityを管理するための領域があり、**データベースアクセスをする場合はPersistence Context内のEntityを取得したり、新規でEntityを登録する必要があります**。

>上記によって、EntityManagerがEntityの状態を追うことができ、適切なタイミングでデータベースと同期を取ることができます。

> EntityManagerにはEntityの状態を変更したり、データベースと同期をとるAPIが用意されています。

https://kohei.life/jpa/

・EntityManagerに対する操作したタイミングでデータベースには反映されず、トランザクションがコミットもしくは強制的に同期(flush)されたタイミングでPersistence Contextに蓄積したEntityへの変更がデータベースへ反映される。

・Persistence Contextはトランザクション単位

・Entity間の紐づけ =@OneToOne等をつけることで関連エンティティを取得できる(LAZY/EAGER)

・Lazy Loading（必要になるまで取得しない）
　...意識しないとクエリ実行タイミングがトランザクション外となりエラーになることもある(´・ω・)

---
### Spring Data

・数ある「Spring Data ---」フレームワークの親玉。
・JPAをもっと使いやすくする「Spring Data JPA」に始まり、DB関連の便利なフレームワークが沢山ある

>  This is **an umbrella project which contains many subprojects** that are specific to a given database.
> https://spring.io/projects/spring-data

---
### Spring Data JPA

・JPAを使いやすくしてくれる抽象クラス/インタフェース群を提供
・**これはJPAの実装ではない。あくまで"JPAという仕様を使いやすくしたもの"である。**

> Spring Data JPAを使わない場合、EntityManagerを直接操作する必要がある。
> Spring Data JPAを使う場合、フレームワーク側で用意されているメソッド（findByXxx・save・saveAll等）を呼び出すだけでDB操作が可能。

・下記のようにインタフェース(CrudRepository)を継承するだけでいい。
　自分でJPQLを作成したければ@Queryを使えばよい。

```java
import org.springframework.streotype.Repository;
import org.springframework.data.repository.CrudRepository;

@Repository
public inteface HogeRepository extends CrudRepository<HogeEntity, String> {

  // 自分でクエリを定義する
  @Query(value = "SELECT DISTINCT hoge from HogeEntity hoge WHERE ~~~~ ");
  List<HogeEntity> findHogeBy~~~(@Param("fuga") String fuga);

}
```


---
### JDBC(Spring JDBC)とJPA(Spring Data JPA)の比較

・大きな違いは「SQLを自分で書くかどうか」

　JDBC：自分でNativeなSQLを書く。
　JPA：SQLを自動生成してくれる。またJPAだけで使えるクエリ言語「JPQL」を使える。

> JPQL...普通のSQLと違うところは「Entity間の紐付けをいい感じにやってくれる」ところ

　JPA(Hibernate)で勝手にSQL作って発行してくれるのは便利だしコーディングがすぐ終わる良さもある。
　しかし　SQLが実行されるタイミングが分かりづらかったり裏側で何が起こっているのか見えづらい
　ので、何をとるかでJDBC・JPAを採択するかは変わってくるだろう。

---