Spring Data JPAとは
データベースのやり取りはJavaに限らずほとんどのサーバーサイドのアプリケーションで必要となる機能ですが、データベース関連のJavaライブラリやフレームワークは無数に存在するため、どれを使えばわからないと困っている方も多いと思います。
Spring Data JPAはそんなデータベース周りのフレームワークの一つですが、いったいどういうものなのか。
公式ページの説明によれば
Spring Data JPAはJPAのレポジトリサポートを提供し、JPAのデータソースにアクセスするアプリケーションの開発を容易にします
とありますが、これだけだとちょっとわからないですね。
Spring Data JPAは、立ち位置的には他のライブラリよりも高いレイヤーに位置していて、他のライブラリと競合することなくデータベース関係のコーディングを極限まで減らしてくれます。
そこで百聞は一見に如かず。Spring Data JPAを使ったコードの例を見てみましょう。
public interface UserRepository extends JpaRepository<User, Long> { }
上のコードは空っぽのインターフェイスですが、これだけでデータベースとやりとりをしてUserデータの読み書きが行えるようになります。
その秘密は継承したJpaRepositoryにあります。IDEでみると、まだ何も書いていないのに以下のメソッドがすでに定義されています。
find (SELECT)、delete (DELETE)、save (INSERTまたはUPDATE)といった基本操作がすでに提供されていますね。実際のコードはSpring Data JPAが自動的に生成してくれるので、アプリケーションの開発者は一行もコーディングせずに利用できるのです。
さらに、あらかじめ決まった命名規則に従ってメソッドを定義するだけで、SELECT文の条件をカスタマイズすることもできます。以下の例をみてみましょう。
public interface UserRepository extends JpaRepository<User, Long> { User findByName(String name); List<User> findByAgeGreaterThan(int age); }
最初のfindByName
メソッドからは、SELECT * FROM USER WHERE NAME = ?
というSQLが、findByAgeGreaterThan
ならば、SELECT * FROM USER WHERE AGE > ?
というSQLが生成されます。これもSpring Data JPAがメソッド名を解析して自動で行ってくれるので、自分でSQLやコードを書く必要は一切ありません。
これによってデータベース関連のコード量が大幅に減り、信頼できるフレームワークのためコードの品質も大幅に改善します。そして開発者は自分のアプリケーション本体のコーディングに専念することができます。
Spring Data JPAの立ち位置
Spring Data JPAは、既存のデータベース関連の標準やライブラリと活用しているので、他のライブラリと競合や矛盾をすることなく自然な形で取り入れることができます。その概略を図にすると以下のようになります。
Javaにおけるデータベースの開発は、上の図に示した①〜④の順番に進化をしてきました。ここではそれぞれのアプローチとその問題点等について踏み込んでいきましょう。
① JDBCで直接書くスタイル
Javaにおいてはかなり早い段階からJDBCと呼ばれるデータベースとのやりとりに関する規約が存在していました。JDBCはマイクロソフトが考案したODBC (Open DataBase Connectivity)のJava版で、異なるデータベースごとの違いを吸収する共通のAPIとして使われます。
上図の一番下にあるように、世の中には無数のデータベースシステムが存在します。Oracleなどのエンタープライズ向けの重量級システムもあれば、MySQLやMariaDBといった無償で幅広く人気のあるもの、そしてSQLiteやH2といったスマホやメモリ内だけで動作するものまで幅広くあります。
ネットワーク上の通信やデータの構造などの内部仕様はシステムごとに異なりますが、各データベースのベンダは、これらの内部仕様を公開するのではなく、JDBCの共通の仕様に準拠したドライバを提供します。これを使うことで、アプリケーション側はあくまでJDBCのAPIを利用することで、データベースの内部仕様を知ることなくさまざまなデータベースとやりとりが行えます。
JDBCのAPIでSQL文を実行することができるので、Java初期の頃は、自分の使っているデータベースに合わせたSQLを直に書いてJDBCのAPIで呼び出すというのが普通でした。
しかしJDBCの問題は、コードが煩雑になりすぎることと、上述のようにデータベース固有のコードになりやすい点があります。千行を超える巨大なクラスの中にOracle固有のSQL文が書かれていたりと、品質も不確かで可搬性も低いコードとなってしまいます。
Spring FrameworkにSpring JDBCというモジュールがあり、JDBCコーディングをスッキリさせるための仕組みが用意されていますが、これから新規で始めるプロジェクトは最初からSpring Data JPAを使用して、JDBCを直に呼び出すのは他に回避先がないとき限定するべきでしょう。
② HibernateなどORM
JDBCの煩雑さを、データベースによって微妙に異なるSQLやデータ型、データを読み書きするたびに発生するJavaオブジェクトとSQLとの変換、またリレーショナルデータベースとJavaにおけるオブジェクトの扱いの違い(インピーダンスミスマッチ)があり、こうした問題を解決するためにORM(Object-Relational Mapping)という技術が生まれ、Hibernateがデファクトスタンダードとなりました。
これによってSQLを直に書くJDBCプログラミングは減りましたが、今度はHibernateで覚えることが多く、Hibernateだけで分厚い本ができるほどでした。
ここに対してもSpringはSpring ORMというモジュールを提供していますが、これから始めるプロジェクトであれば使う必要はありません。
③ JPA (Java Persistence API)の登場
ORMツールの普及に伴い、こうした仕組みをJavaの標準に取り込む動きが進み、その結果としてJPAが定義されました。JPAのかなりの部分はHibernateから引き継いだものですが、標準APIとなったことで固有のフレームワークに依存するという問題(ベンダーロックイン)は緩和されたと思います。
Hibernateと同様のフレームワークとしてEclipseLinkやOpenJPAなどがありますが、これらはJPAを実装しているので、理論上は切り替えが可能となりましたが、僕個人としてはHibernate以外を使ったことがありませんし、Spring BootなどのプロジェクトもHibernateを選択しているので、Hibernateが最も使われている状況には変わりがないと思います。
④ Spring Data JPAで快適に
JPAによってデータベース関連の仕様が標準化されたものの、それでもデータアクセスに関しては煩雑さが残っていました。
JPAではデータベースとやりとりするためのDAO (Data Access Object)と呼ばれるクラスを作り、そこにデータを読み書きする似たようなボイラープレートコードを書く必要があり、扱うオブジェクトの数が増えるとこの作業はかなり面倒でコード量も膨れ上がります。
この問題を解決するために生まれたのがSpring Data JPAでした。これによって、冒頭でも紹介したようにほとんどコードを書くことなくデータベースへのアクセスが行えるようになりました。
Springのプロジェクトは非常に設計が優れていて、基礎となるSpring Frameworkのプログラミング手法との整合性が非常に高く一貫した開発ができるのもメリットです。ベンダーロックインは一般的には悪いことだけど、「Springになら囲い込まれてもイイ!」なんて僕は思っています。
関連、参考文献
Spring Data JPA(英語のオフィシャルページ)