Hibernate:save,persist,update,merge,saveOrUpdate

はじめに

この記事では、セッションインターフェイスのいくつかのメソッドの違いについて説明します。save,persist,update,merge,saveOrUpdate。

これはHibernateの紹介ではなく、設定、オブジェクトリレーショナルマッピング、エンティティインスタンスの操作の基本を既に知っている必要があります。 Hibernateの入門記事については、Springを使用したHibernate4のチュートリアルを参照してください。

続きを読む:

Hibernateでオブジェクトを削除する

Hibernateでエンティティを削除するためのクイックガイド。
続きを読む→

Hibernate

を使用したストアドプロシージャこの記事では、Hibernateからストアプロシージャーを呼び出す方法について簡単に説明します。
続きを読む→

hibernate/JPAの識別子の概要

hibernateでエンティティ識別子をマップする方法を学びます。
続きを読む→

Session as A Persistence Context Implementation

Sessionインターフェイスには、最終的にデータベースにデータを保存するいくつかのメソッドがあります。persist、save、update、merge、saveOrUpdate。 これらのメソッドの違いを理解するには、まず永続コンテキストとしてのセッションの目的と、セッションに関連するエンティティインスタンスの状態の違いについて議論する必要があります。

APIメソッドの一部が重複したHibernate開発の歴史も理解する必要があります。

2.1. エンティティインスタンスの管理

オブジェクト-リレーショナル-マッピング自体とは別に、Hibernateが解決しようとしていた問題の一つは、実行時にエン “永続性コンテキスト”の概念は、この問題に対するHibernateの解決策です。 永続性コンテキストは、セッション中にデータベースにロードまたは保存したすべてのオブジェクトのコンテナまたは第一レベルのキャッシュと考

セッションは論理トランザクションであり、境界はアプリケーションのビジネスロジックによって定義されます。 永続コンテキストを使用してデータベースを操作し、すべてのエンティティインスタンスがこのコンテキストにアタッチされている場合は、セッショ

Hibernateでは、永続性コンテキストはorgで表されます。冬眠。セッションインスタンス。 JPAの場合、それはjavaxです。永続性。EntityManager。 HibernateをJPAプロバイダとして使用し、EntityManagerインターフェイスを介して操作する場合、このインターフェイスの実装は基本的に基礎となるSessionオブジェクトをラッ しかし、Hibernate Sessionはより豊富なインターフェイスを提供し、より多くの可能性を提供するため、Sessionを直接操作すると便利な場合があります。

2.2. エンティティインスタンスの状態

アプリケーション内のエンティティインスタンスは、セッション永続化コンテキストに関連して、三つの主な状:

  • transient-このインスタンスはセッションにアタッチされておらず、決してアタッチされていません。;
  • persistent—このインスタンスは一意のSessionオブジェクトに関連付けられています。セッションをデータベースにフラッシュすると、このエンティティはデータベース内に対応する一貫性のあるレコードを持つことが保証されます。
  • detached—このインスタンスはかつてセッションにアタッチされていました(永続状態)が、現在はアタッチされていません。インスタンスをコンテキストから削除したり、セッションをクリアまたはクローズしたり、インスタンスをシリアル化/逆シリアル化プロセスに入れたりすると、インスタンスがこの状態になります。

ここでは、状態遷移を実現するセッションメソッドに関するコメントを含む簡略化された状態図です。

2016-07-11_13-38-11

エンティティインスタンスが永続状態の場合、このインスタンスのマップされたフィールドに加えたすべての変更は、セッションのフラッシュ時に対応するデータベースレコードおよびフィールドに適用されます。 永続インスタンスは”オンライン”と考えることができますが、デタッチされたインスタンスは”オフライン”になり、変更は監視されません。

これは、永続オブジェクトのフィールドを変更するときに、save、update、またはこれらのメソッドのいずれかを呼び出してデータベースに変更を取得する必要がな

2.3. Jpa仕様

への準拠は、Hibernateが最も成功したJava ORM実装でした。 Java persistence API(JPA)の仕様がHibernate APIの影響を大きく受けているのも不思議ではありません。 残念ながら、多くの違いもありました:いくつかの主要な、いくつかのより微妙な。

JPA標準の実装として機能するには、Hibernate Apiを改訂する必要がありました。 EntityManagerインターフェイスに一致するように、いくつかのメソッドがセッショ これらのメソッドは、”元の”メソッドと同じ目的を果たしますが、仕様に準拠しているため、いくつかの違いがあります。

操作の違い

すべてのメソッド(persist、save、update、merge、saveOrUpdate)がすぐに対応するSQL UPDATEまたはINSERTステートメントになるわけではないことを最初から理解することが重要 データベースへのデータの実際の保存は、トランザクションのコミット時またはセッションのフラッシュ時に行われます。

上記の方法は、基本的に、エンティティインスタンスの状態をライフサイクルに沿って異なる状態間で移行することによって管理します。

エンティティの例として、単純な注釈マップされたエンティティPersonを使用します:

@Entitypublic class Person { @Id @GeneratedValue private Long id; private String name; // ... getters and setters}

3.1. Persist

persistメソッドは、永続コンテキストに新しいエンティティインスタンスを追加すること、つまりインスタンスをtransient状態からpersistent状態に移行することを目的としています。

私たちは通常、データベースにレコードを追加したいときにそれを呼び出します(エンティティインスタンスを永続化します):

Person person = new Person();person.setName("John");session.persist(person);

persistメソッドが呼び出された後はどうなりますか? Personオブジェクトがtransient状態からpersistent状態に移行しました。 オブジェクトは現在永続コンテキストにありますが、データベースにはまだ保存されていません。 INSERTステートメントの生成は、トランザクションのコミット、フラッシュ、またはセッションの終了時にのみ行われます。

persistメソッドにはvoid戻り値の型があることに注意してください。 渡されたオブジェクトを”所定の位置に”操作し、その状態を変更します。 Person変数は、実際の永続化されたオブジェクトを参照します。

このメソッドは、セッション-インターフェースの後に追加されたものです。 この方法の主な差別化の特徴は、JSR-220仕様(EJB永続性)に準拠していることです。 このメソッドのセマンティクスは仕様で厳密に定義されており、基本的には次のように述べています:

  • 一時的なインスタンスは永続的になり(操作はcascade=PERSISTまたはcascade=ALLとのすべての関係にカスケードします)、
  • インスタンスがすでに永続的である場合、この呼…..

ここではインスタンスの識別子に関係するものは何もないことに注意してください。 仕様では、id生成戦略に関係なく、idがすぐに生成されるとは述べていません。 Persistメソッドの仕様では、実装がcommitまたはflushでidを生成するステートメントを発行することができ、このメソッドを呼び出した後にidがnull以外であるこ

既に永続的なインスタンスでこのメソッドを呼び出すことができますが、何も起こりません。 しかし、分離されたインスタンスを永続化しようとすると、実装は例外をスローするようにバインドされます。 次の例では、エンティティを永続化し、コンテキストから削除してデタッチされるようにしてから、再度永続化を試みます。 セッションへの2回目の呼び出し。persist()は例外を発生させるため、次のコードは機能しません:

Person person = new Person();person.setName("John");session.persist(person);session.evict(person);session.persist(person); // PersistenceException!

3.2. Save

saveメソッドは、JPA仕様に準拠していない”元の”Hibernateメソッドです。

その目的は基本的にpersistと同じですが、実装の詳細が異なります。 このメソッドのドキュメントには、”最初に生成された識別子を割り当てる”というインスタンスを永続化することが厳密に記載されています。 このメソッドは、この識別子の直列化可能な値を返すことが保証されています。

Person person = new Person();person.setName("John");Long id = (Long) session.save(person);

既に永続化されているインスタンスを保存する効果は、persistと同じです。 分離されたインスタンスを保存しようとすると、違いが生じます:

Person person = new Person();person.setName("John");Long id1 = (Long) session.save(person);session.evict(person);Long id2 = (Long) session.save(person);

id2変数はid1とは異なります。 デタッチされたインスタンスでsaveを呼び出すと、新しい永続インスタンスが作成され、新しい識別子が割り当てられます。

3.3. Merge

mergeメソッドの主な目的は、分離されたエンティティインスタンスの新しいフィールド値で永続エンティティインスタンスを更新することです。

たとえば、JSONシリアル化されたオブジェクトをそのidで呼び出し元に取得するメソッドと、呼び出し元からこのオブジェクトの更新バージョンを受 このようなシリアル化/逆シリアル化を通過したエンティティは、デタッチされた状態で表示されます。

このエンティティインスタンスを逆シリアル化した後、永続コンテキストから永続エンティティインスタンスを取得し、そのフィールドをこのデ したがって、mergeメソッドは正確にそれを行います:

  • 渡されたオブジェクトから取得したidでエンティティインスタンスを検索します(永続コンテキストの既存のエンティティインスタンスが取得されたか、またはデータベースからロードされた新しいインスタンスのいずれか)。
  • 渡されたオブジェクトからこのインスタンスにフィールドをコピーします。
  • は新しく更新されたインスタンスを返します。

次の例では、保存されたエンティティをコンテキストから削除(デタッチ)し、名前フィールドを変更してから、デタッチされたエンティティをマージします。

Person person = new Person(); person.setName("John"); session.save(person);session.evict(person);person.setName("Mary");Person mergedPerson = (Person) session.merge(person);

mergeメソッドはオブジェクトを返すことに注意してください—これは、永続コンテキストにロードされ、更新されたmergedPersonオブジェクトであり、引数として渡したperson これらは2つの異なるオブジェクトであり、personオブジェクトは通常破棄する必要があります(とにかく、永続性コンテキストに添付されていること

persistメソッドと同様に、mergeメソッドはJSR-220によって指定され、信頼できる特定のセマンティクスを持つように指定されています:

  • エンティティがデタッチされると、既存の永続エンティティにコピーされます。
  • エンティティが一時的な場合は、新しく作成された永続エンティティにコピーされます。
  • この操作は、cascade=MERGEまたはcascade=ALLマッピングを持つすべてのリレーションに対してカスケードされます。
  • エンティティが永続的な場合、このメソッド呼び出しはそれには影響しません(ただし、カスケードは行われます)。

3.4. Update

persistおよびsaveと同様に、updateメソッドはmergeメソッドが追加されるずっと前に存在していた”元の”Hibernateメソッドです。 その意味論はいくつかの重要な点で異なります:

  • updateメソッドは、渡されたオブジェクトをdetachedからpersistent状態に遷移させます。
  • このメソッドは、transientエンティティを渡すと例外をスローします。

次の例では、オブジェクトを保存し、コンテキストからオブジェクトを削除(デタッチ)してから、その名前を変更してupdateを呼び出します。 更新はpersonオブジェクト自体で行われるため、更新操作の結果を別の変数に入れないことに注意してください。 基本的には、既存のentityインスタンスを永続コンテキストに再アタッチしています—JPA仕様では許可されていないことです。

Person person = new Person();person.setName("John");session.save(person);session.evict(person);person.setName("Mary");session.update(person);

一時的なインスタンスでupdateを呼び出そうとすると、例外が発生します。 以下は機能しません:

Person person = new Person();person.setName("John");session.update(person); // PersistenceException!

3.5. SaveOrUpdate

このメソッドはHibernate APIにのみ表示され、対応する標準化されたものはありません。 Updateと同様に、インスタンスの再接続にも使用できます。

実際には、updateメソッドを処理する内部D E FaultupdateeventlistenerクラスはD E Faultsaveorupdatelistenerのサブクラスであり、一部の機能をオーバーライドするだけです。 SaveOrUpdateメソッドの主な違いは、一時的なインスタンスに適用されたときに例外をスローしないことです。 次のコードは、Personの新しく作成されたインスタンスを保持します:

Person person = new Person();person.setName("John");session.saveOrUpdate(person);

このメソッドは、一時的または分離されているかどうかにかかわらず、オブジェクトを永続的にするための普遍的なツールと考えることができます。

何を使う?

特別な要件がない場合は、経験則として、persistメソッドとmergeメソッドは標準化され、JPA仕様に準拠することが保証されているため、persistメソッドとmergeメソッ

別の永続化プロバイダに切り替えることにした場合にも移植可能ですが、”元の”Hibernateメソッド、save、update、saveOrUpdateほど有用ではないように見えることがあります。

結論

実行時の永続エンティティの管理に関連して、さまざまなHibernateセッションメソッドの目的について説明しました。 私たちは、これらのメソッドがライフサイクルを通じてエンティティインスタンスをどのようにtransistするか、そしてこれらのメソッ



+