Hibernate:session.getとsession.loadの違い


88

APIから、プロキシと関係があることがわかりました。しかし、私は、プロキシ上で多くの情報を見つけることができなかったと呼び出しの違いを理解していないsession.getとしますsession.load。誰かが私を説明したり、参照ページに案内したりできますか?

ありがとうございました!!

回答:


117

Hibernateフォーラムから:

これは、Hibernate in Actionの本からです。良い人はこれを読んだ。


識別子によるオブジェクトの取得次のHibernateコードスニペットは、データベースからUserオブジェクトを取得します。

User user = (User) session.get(User.class, userID);

識別子はクラスの単一のインスタンスを一意に識別するため、get()メソッドは特別です。したがって、アプリケーションが永続オブジェクトへの便利なハンドルとして識別子を使用するのは一般的です。識別子による取得では、オブジェクトを取得するときにキャッシュを使用して、オブジェクトがすでにキャッシュされている場合のデータベースヒットを回避できます。Hibernateはload()メソッドも提供します:

User user = (User) session.load(User.class, userID);

load()メソッドは古いです。get()は、ユーザーの要求によりHibernateのAPIに追加されました。違いは簡単です:

load()がキャッシュまたはデータベースでオブジェクトを見つけられない場合、例外がスローされます。load()メソッドがnullを返すことはありません。オブジェクトが見つからない場合、get()メソッドはnullを返します。

load()メソッドは、実際の永続インスタンスの代わりにプロキシを返す場合があります。プロキシは、実際にオブジェクトに初めてアクセスしたときに、実際のオブジェクトのロードをトリガーするプレースホルダーです。一方、get()はプロキシを返しません。get()とload()のどちらかを選択するのは簡単です。永続オブジェクトが存在し、存在しないことが例外と見なされる場合は、load()が適切なオプションです。指定された識別子を持つ永続インスタンスがあるかどうかわからない場合は、get()を使用して戻り値をテストし、nullかどうかを確認します。load()を使用すると、さらに影響があります。アプリケーションは、データベースにアクセスして永続的な状態を取得することなく、永続的なインスタンスへの有効な参照(プロキシ)を取得できます。そのため、load()は、キャッシュまたはデータベースで永続オブジェクトを見つけられない場合でも例外をスローしない場合があります。例外は、後でプロキシにアクセスしたときにスローされます。もちろん、識別子によるオブジェクトの取得は、任意のクエリを使用するほど柔軟ではありません。


1
私はsession.Get <T>()がプロキシを返す問題を今デバッグしています!
Kent Boogaart

7
どうもありがとう!「load()がキャッシュまたはデータベースでオブジェクトを見つけられない場合、例外がスローされます。オブジェクトが見つからない場合、get()メソッドはnullを返します。」
Chris

15
Session.getのJavaDocは、次のように述べています。指定された識別子を持つ指定されたエンティティークラスの永続インスタンスを返すか、そのような永続インスタンスがない場合はnullを返します。(インスタンス、またはインスタンスのプロキシがすでにセッションに関連付けられている場合は、そのインスタンスまたはプロキシを返します。)したがって、「get()はプロキシを返しません」という本のセクション。不正解です。
Vicky、

DAOSでトランザクション管理戦略を使用している場合は、get()を使用することをお勧めします。そうでない場合、load()がプロキシを返す場合に備えて、呼び出し元も開いている休止状態セッションのコンテキストで実行する必要があります。たとえば、MVCを実行している場合、有効なセッションがない場合、コントローラーがdao.load()を実行し、後でプロキシオブジェクトにアクセスしようとすると例外をスローすることがあります。dao.get()を実行すると、セッションに関係なく、実際のオブジェクトがコントローラに返されます(存在する場合)
dev

@Vickyが説明した問題は頭痛の種となる可能性があり、私はそれの利点を何も見ていません。場合によっては、さらにパラメーター化されたクエリの識別子が必要になります。ただし、オブジェクトのプロキシがすでにセッションにあるため、識別子のゲッターはnullを返します。プロキシがセッションにある場合、なぜ実際のインスタンスではなくプロキシを取得するのですか?
djmj

15

まあ、少なくともnhibernateでは、session.Get(id)はデータベースからオブジェクトをロードしますが、session.Load(id)はサーバーを離れることなくそれにプロキシオブジェクトを作成するだけです。POCO(またはPOJO :)の他のすべての遅延読み込みプロパティと同じように機能します。次に、このプロキシをオブジェクト自体への参照として使用して、関係を作成できます。

Idのみを保持し、必要に応じて残りをロードするオブジェクトがあると考えてください。(FKなどの)関係を作成するために渡すだけの場合は、IDだけで十分です。


つまり、load(id)は最初にデータベースにアクセスして有効なIDかどうかを確認し、プロキシオブジェクトを返します。このオブジェクトのプロパティにアクセスすると、データベースに再度アクセスします。ありそうもないシナリオではないですか?単一のオブジェクトをロードするための2つのクエリ?
faisalbhagat 2014

いいえ、load(id)はIDをまったく検証しないため、DBへのラウンドトリップはありません。有効であると確信している場合にのみ使用してください。
ホルヘアルベス

9

session.load()は、データベースにアクセスすることなく、常に「プロキシ」(Hibernate用語)を返します。Hibernateでは、プロキシは指定された識別子の値を持つオブジェクトであり、そのプロパティはまだ初期化されていません。一時的な偽のオブジェクトのように見えます。行が見つからない場合、ObjectNotFoundExceptionがスローされます。

session.get()は常にデータベースにヒットし、実際のオブジェクト(プロキシではなくデータベース行を表すオブジェクト)を返します。行が見つからない場合は、nullを返します。

これらのメソッドでのパフォーマンスもdiffになります。2つの間に...


3

もう一つ余分なポイント::

Hibernate Sessionクラスのgetメソッドは、データベースと同様にキャッシュにもオブジェクトが見つからない場合、nullを返します。一方、データベースだけでなくキャッシュにもオブジェクトが見つからず、nullを返さない場合、load()メソッドはObjectNotFoundExceptionをスローします。


2

「get」の代わりに「load」を使用した間接的な結果の1つは、バージョン属性を使用した楽観的ロックが期待どおりに機能しない可能性があることです。ロードが単にプロキシを作成し、データベースから読み取らない場合、バージョンプロパティはロードされません。バージョンは、後でオブジェクトのプロパティを参照したときにのみ読み込まれ、選択がトリガーされます。それまでの間、別のセッションでオブジェクトを更新することができ、セッションにはオプティミスティックロックチェックを実行するために必要な元のバージョンがありません。そのため、セッションの更新は他のセッションの更新を警告なしで上書きします。

これは、同じ識別子を持つオブジェクトを使用する2つのセッションでこのシナリオをスケッチする試みです。DB内のオブジェクトの初期バージョンは10です。

Session 1                  Session 2
---------                  ---------
Load object
Wait a while..   
                           Load object
                           Modify object property
                           [triggers db 'select' -
                            version read as 10]
                           Commit
                           [triggers db update,
                            version modified to 11]
Modify object property
  [triggers db 'select' -
  version read as 11]
Commit
  [triggers db update,
  version modified to 12]

実際には、セッション1のコミットが楽観的ロック例外で失敗することを望んでいますが、ここでは成功します。

「load」の代わりに「get」を使用すると、問題が回避されます。これは、getがすぐにselectを発行し、楽観的ロックチェックの正しいタイミングでバージョン番号がロードされるためです。


0

また、オブジェクトが存在しない場合は例外をスローするため、loadの使用中は注意が必要です。オブジェクトが存在することが確実な場合にのみ使用する必要があります。


0

優れた説明はhttp://www.mkyong.com/hibernate/different-between-session-get-and-session-load
session.load()にあります。
これは常に、データベースを打つ。
Hibernateでは、プロキシは指定された識別子の値を持つオブジェクトであり、そのプロパティはまだ初期化されていません。一時的な偽のオブジェクトのように見えます。
ID値がデータベースに存在しない場合でも、指定されたID値を持つプロキシオブジェクトを常に返します。ただし、データベースからプロパティを取得してプロキシを初期化しようとすると、selectステートメントでデータベースにヒットします。行が見つからない場合、ObjectNotFoundExceptionがスローされます。
session.get():
常にデータベースにヒットし(キャッシュに見つからない場合)、実際のオブジェクト(プロキシではなく、データベース行を表すオブジェクト)を返します。
行が見つからない場合は、nullを返します。


0

load()はキャッシュまたはデータベースからオブジェクトを見つけることができず、例外がスローされ、load()メソッドはnullを返しません。

get()メソッドは、オブジェクトが見つからない場合はnullを返します。load()メソッドは、実際の永続インスタンスではなくプロキシを返す場合がありますget()はプロキシを返しません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.