知識

⭐️ Criteria APIとHibernateの違い

0 likes

Criteria APIとHibernateは、Javaのデータ永続化(ORM)において異なるレイヤーの話であり、一言で言えば**「標準規格(ルール)」と「その実装(製品)」**の関係にあります。

しかし、歴史的な経緯から「Hibernate独自のCriteria」も存在するため、混乱を避けるために整理して解説します。


1. 根本的な役割の違い

まず、全体像を把握するための関係図は以下の通りです。

項目JPA Criteria APIHibernate
分類インターフェース(仕様)フレームワーク(実装)
立ち位置Jakarta Persistence (旧JPA) という標準規格の一部。JPAという規格を実際に動かすための「エンジン」。
役割型安全なクエリを構築するための「書き方」を定義。データベースとの接続、SQL生成、キャッシュ管理など。
互換性規格なので、EclipseLinkなど他の実装でも使える。Hibernate独自の機能を使うと他の実装への切り替えが困難。

2. クエリ構築における違い

「Criteria API」は、Javaコードを使って動的にクエリを組み立てるための仕組みです。一方で「Hibernate」には、このCriteria APIを動かす機能以外にも、HQL(Hibernate Query Language)などの書き方があります。

データの取得方法の比較

  1. Hibernate(HQL/JPQL):
    • 文字列でクエリを書く。
    • "FROM User WHERE name = :name"
    • メリット: 直感的で読みやすい。
    • デメリット: タイポ(打ち間違い)が実行時まで分からない。
  2. Criteria API:
    • Javaのメソッドを組み合わせて書く。
    • cb.equal(user.get("name"), "Taro")
    • メリット: 型安全(Type-safe)。コンパイル時にエラーを検知できる。IDEの補完が効く。
    • デメリット: コードが冗長になりやすく、複雑なクエリは読みにくい。

3. 「Hibernate Criteria」という古い存在

ここが最も混乱を招くポイントですが、実はCriteriaには2種類あります。

  • Hibernate Criteria (Legacy):
    • JPAが普及する前に、Hibernateが独自に提供していた古いAPIです。
    • 現在は**非推奨(Deprecated)**となっており、使うべきではありません。
  • JPA Criteria API:
    • 現在の標準です。Hibernateも現在はこのJPA標準のCriteria APIを使うことを推奨しています。

どちらを意識すべきか?

現在、Javaでデータベース操作を行う場合、基本的には**「JPA Criteria API」というルールを使って、裏側で「Hibernate」というエンジンを動かしている**状態になります。

使い分けの基準

  • 単純な検索や、決まりきったクエリ: 文字列で記述するJPQL(またはSpring Data JPAのメソッド名による生成)の方が、コードが短く可読性が高いため推奨されます。
  • 検索条件が動的に変わる画面(検索フォームなど): if文などで文字列を連結するとバグの温床になるため、プログラムでクエリを組み立てるCriteria APIが真価を発揮します。

まとめると、Hibernateは「大きな箱(フレームワーク)」であり、Criteria APIはその中にある「高度なクエリを組み立てるためのツール」の一つだと捉えるのが正解です。

Java->criteriaAPI->hibernate->DB

その認識で、概ね間違いありません。 非常に的確なイメージです。

より正確に、データの流れと役割を分解すると以下のようになります。


データアクセスのフロー詳細

  1. Java (アプリケーション層) 「こういうデータが欲しい」というロジックを、Criteria API を使ってJavaコードとして記述します。
  2. Criteria API (JPA規格層) ここで「型安全なクエリの設計図」が作られます。しかし、これ自体は単なる「インターフェース(ルール)」なので、実体はありません。
  3. Hibernate (ORM実装層) Hibernateがその「設計図」を読み取り、実行環境(MySQLやPostgreSQLなど)に合わせた最適な SQL に翻訳します。
  4. JDBC (接続層 / ドライバ) Hibernateが生成したSQLを、Java標準のデータベース接続機能である JDBC を介してデータベースに送信します。
  5. DB (データベース層) SQLを実行し、結果を返します。

処理のイメージ例

「名前が 'M' で始まるユーザーを取得する」という処理を例にすると、役割分担は以下のようになります。

ステップ担当実際の動きのイメージ
指示Java (Criteria)cb.like(root.get("name"), "M%") と書く。
翻訳Hibernate「これは SELECT * FROM users WHERE name LIKE 'M%' だな」とSQLを作る。
運搬JDBCそのSQLをデータベースへ運び、結果を持ち帰る。
変換HibernateDBから返ってきた表形式のデータを、再び Javaのインスタンス(Entity) に詰め直す。

補足:なぜ間にいろいろ挟むのか?

直接SQLを書かずにこのフローを通る最大のメリットは、「DBの種類が変わっても、Javaのコードを書き直さなくて済む」 ことにあります。

Hibernateが「方言(Dialect)」を吸収してくれるため、OracleからPostgreSQLに乗り換えても、Java側のCriteria APIのコードはそのまま動くのがこのアーキテクチャの強みです。

joinやサブクエリはJPQLがいい

基本的には**「可読性(読みやすさ)」を重視するなら、JPQLの方がおすすめ**です。

Joinやサブクエリが絡む複雑なクエリをCriteria APIで書こうとすると、コードが非常に長く、直感的に理解しにくいものになってしまうからです。

それぞれの使い分けのポイントを整理しました。


1. なぜ複雑なクエリはJPQLがいいのか?

JPQLの場合

SQLに近い感覚で書けるため、構造が一目でわかります。

Criteria APIの場合

型安全ではありますが、手続きが非常に多くなります。

これにサブクエリが加わると、さらにSubqueryオブジェクトの定義や相関条件の設定が必要になり、数行のSQLを表現するのに数十行のJavaコードを書くことも珍しくありません。


2. JPQL vs Criteria API 比較

特徴JPQLCriteria API
可読性高い(SQLに近い)低い(冗長になりがち)
複雑なJoin楽に書ける記述がかなり大変
サブクエリ直感的構造が複雑になる
型の安全性低い(文字列のため)高い(コンパイルエラーで気付く)
動的な条件変更苦手(文字列結合が必要)得意(if文でパーツを追加できる)

3. 使い分けのガイドライン

今の開発現場でよく採用される「現実的な使い分け」は以下の通りです。

  1. JPQLを使うべきケース
    • クエリの構造が固定されている(Join先やサブクエリの形が決まっている)。
    • 後から見たときに「何をしているクエリか」をすぐ把握したい。
  2. Criteria APIを使うべきケース
    • 「ユーザーが画面で選択した項目によって、JoinするテーブルやWHERE句の条件がバラバラに変わる」といった動的クエリ
    • テーブル名やカラム名の変更に強くしたい(リファクタリング耐性重視)。

結論

Joinやサブクエリが必要なほど複雑なロジックであれば、まずはJPQLで書いてみて、もし「検索条件が多すぎて文字列操作(if文での連結など)が辛い」と感じた場合にのみ、Criteria APIを検討するのが最も効率的です。