Hibernate ORM 5.0のリリースから6年半、Red Hatは、同社のフラッグシッププロダクトとして人気の高い、オブジェクト-リレーショナルマッピング永続化ユーティリティのHibernate ORMのバージョン6.0をリリースした。注目の新機能は、Jakarta 3.0仕様へのマイグレーション、JDBCのパフォーマンス向上、HQLトランザクション、クライテリアトランザクション(criteria translation)などだ。また、今回のリリースから、最低要件がJava 11になった。
Hibernate 6.0では、Java PersistenceはJava EE下のJava Persistence APIには定義されず、Jakarta EE配下のJava Persistence 3.0に移動している。これはまた、javax.persistence
パッケージが使用できなくなった、という意味でもある。今後は開発者が、自身のJavaコードにjakarta.persistence
をインポートしなければならない。実際の例では次のようになる。
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import java.util.Date;
import org.hibernate.annotations.GenericGenerator;
@Entity
@Table(name = "EVENTS")
public class Event {
@Id
@GeneratedValue(generator = "increment")
@GenericGenerator(name = "increment", strategy = "increment")
private Long id;
private String title;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "EVENT_DATE")
private Date date;
public Event() {
// this form used by Hibernate
}
// getter methods
// setter methods
}
Java JDBC APIは、通常のデータベース問合せによって生成されるデータベース結果を表現したResultSet
インターフェースを提供する。クエリ結果からデータを抽出するには、名前指定(read-by-name)と位置指定(read-by-position)という2つの方法があるのだが、今回のリリースで、ResultSet
インスタンスからの読み出しが名前指定から位置指定に変更された。この件に関して、Red Hatのリードソフトウェアエンジニアで、Hibernate ORMのリードデベロッパを務めるSteve Ebersole氏は、リリースノートで次のように説明している。
数年前、5.4の頃、Red Hatの優秀なパフォーマンスチームの協力を得て、Hibernate ORMからさらに優れたパフォーマンスを取り出すことに成功しました。この開発は、WildFlyのパフォーマンスを改善する作業の一環として行われたものです。
その結果として、JDBC ResultSetの値を位置ではなく名前で読み取るというアプローチが、Hibernateのさらなる改良を制限するファクタになりました。どのJDBCドライバであっても、名前による読み取りは遅くなります。
言い換えれば、これは、Firebird JDBCドライバのメンテナであるMark Rotteveel氏がStackOverflowの記事で述べているように、位置指定の方が名前指定よりも高速だ、ということである。
データベースサーバからデータを受信する上で最も自然な方法として、各行の値は、一般的に配列あるいはリストに格納されます。ですから、インデックスによる値の取り出しが最もシンプルなのです。
それに対して、カラム名による検索は処理が多くなります。カラム名は大文字小文字を区別せずに扱われるため、小文字ないし大文字に正規化する追加コストを払うか、TreeMapを使って大小文字を区別しない検索を使用する必要があるからです。
ResultSet
を位置指定読み出しに変更すれば、Hibernate Type Systemも変更することになる。@AnyMetaDef
、@AnyMetaDefs
、@TypeDef
、@TypeDefs
といった非推奨アノテーションを含む、文字列ベースのアプローチによる型指定をすべて排除することになるからだ。Hibernare 6.0ではアノテーションも再設計されており、より型安全になったと言われている。この変更に関心のある開発者は、ユーザガイドを見るとよいだろう。ドメインモデルマッピングの詳細が確認できる。
さらにHibernate 6.0では、位置指定読み出しによる副作用として、生成されるSQL selectクエリで名前付き列のエイリアスを作成する必要がなくなっており、SQLの可読性も向上している。
Hibernate 6.0より前 | Hibernate 6.0 |
select event0_.id as id1_0_, |
select e1_0.id,e1_0.event_date,e1_0.title |
HibernateはHQLという問い合わせ言語を使用している。HQLはSQLによく似ているが、オブジェクト指向であり、継承やポリモーフィズム、アソシエーションといった概念を理解する。
HQLは、構造化テキストやバイナリファイルの読み込み、処理、実行、変換を目的とする強力なパーザジェネレータのANTLRを使って記述されている。今回のバージョンではANTLR 2からANTRL 4にアップグレードされて、HQLがより効率的になった、とリリースノートには記されている。
もうひとつの大きな変更点は、HQLとクライテリアクエリの両方に対処する新しいクエリパーザであるSemantic Query Model (SQM)の採用で、以前のHQLクエリ機能よりも良好なパフォーマンスを提供する、とされている。
今回のリリースでは、Hibernateの古いCriteria APIが削除されて、クライテリアクエリの提供はJakarta Persistence API経由のみとなった。また、そのコントラクトが将来的に変更される可能性のあることを警告する手段として、@Incubating
アノテーションが新たに導入されている。
This release offers many other new features and internal changes. Maven用のアーティファクトはすでにMaven Centralにパブリッシュされているので、すべてのJavaアプリケーションでHibernate 6.0を使用できる。Hibernate 6.0へのマイグレーションに関心のある開発者はマイグレーションガイドを参考にするとよいだろう。新たにHibernateを導入するならば、ユーザ向けのコンセプトやAPIのほとんどを網羅した"Hibernate Getting Started Guide"が便利だ。