web-dev-qa-db-ja.com

Hibernate saveOrUpdateの動作

session.saveOrUpdate()が呼び出されたときにHibernateがデータベース内の値をINSERTするかUPDATEするかをどのように知るかを知っていますか?

これまでのところ、キャッシュ内の情報に依存するものではなく、データベース内のエンティティの存在は主キーによって決定されると判断しました。

40
iliaden

.saveOrUpdate()を使用すると、Hibernateはオブジェクトが一時的(識別子プロパティを持たない)かどうかを確認し、そうであれば識別子を生成してセッションに割り当てることで永続化します。オブジェクトに既に識別子がある場合、.update()を実行します。

ドキュメント から:

saveOrUpdate()は次のことを行います。

  • オブジェクトがこのセッションですでに永続的である場合、何もしません
  • セッションに関連付けられた別のオブジェクトが同じ識別子を持つ場合、例外をスローします
  • オブジェクトに識別子プロパティがない場合、save()
  • オブジェクトの識別子に、新しくインスタンス化されたオブジェクトに割り当てられた値がある場合、save()
  • オブジェクトがまたはによってバージョン管理され、バージョンプロパティ値が新しくインスタンス化されたオブジェクトに割り当てられた値と同じ場合、save()それ以外の場合はオブジェクトをupdate()
41
Rihards

おそらく、Hibernateの聖書を引用すると役立つでしょう( Java Persistence with Hibernate、2nd ed。 、528ページ):

より経験豊富なHibernateユーザーはsaveOrUpdate()を排他的に使用します。特に混合状態のオブジェクトのより複雑なネットワークでは、Hibernateが何が新しく何が古いかを決定するのがはるかに簡単です。排他的なsaveOrUpdate()の唯一の(本当に深刻ではない)欠点は、データベースでSELECTを起動しないとインスタンスが古いか新しいかを推測できないことがあることです。たとえば、クラスは、バージョンまたはタイムスタンププロパティのない自然な複合キーでマップされます。

Hibernateはどのインスタンスが古いインスタンスと新しいインスタンスをどのように検出しますか?さまざまなオプションが利用可能です。 Hibernateは、次の場合にインスタンスが保存されていない一時インスタンスであると想定します。

  • 識別子プロパティはnullです。
  • バージョンまたはタイムスタンププロパティ(存在する場合)はnullです。
  • Hibernateによって内部的に作成された同じ永続クラスの新しいインスタンスは、指定されたインスタンスと同じデータベース識別子の値を持ちます。
  • クラスのマッピングドキュメントで_unsaved-value_を指定すると、識別子プロパティの値が一致します。 _unsaved-value_属性は、バージョンおよびタイムスタンプのマッピング要素にも使用できます。
  • 同じ識別子値を持つエンティティデータは、2次キャッシュにありません。
  • 実装または_org.hibernate.Interceptor_を指定し、コード内のインスタンスをチェックした後、Interceptor.isUnsaved()から_Boolean.TRUE_を返します。
10
jhegedus

前述のように、 heresaveOrUpdateは、新しい識別子を生成して一時的なインスタンスを保存するか、現在の識別子に関連付けられた分離されたインスタンスを更新/再接続します。より具体的には:

  • オブジェクトがこのセッションですでに永続的である場合、何もしません
  • セッションに関連付けられた別のオブジェクトが同じ識別子を持つ場合、例外をスローします
  • オブジェクトに識別子プロパティがない場合、save() it
  • オブジェクトの識別子に、新しくインスタンス化されたオブジェクトに割り当てられた値がある場合、save()
  • オブジェクトが_<version>_または_<timestamp>_によってバージョン管理され、バージョンプロパティ値が
  • 新しくインスタンス化されたオブジェクトに割り当てられた同じ値、save() it
  • それ以外の場合はupdate()オブジェクト
2
bpgergo

誰かが理論的に本当に理解していないなら、コードがあります

MyModel sent = myDao.myDaoImpl(id); 

if(sent == null){                        
    sent = **new MyModel();** // new Object
    sent.setXX(id);
    sent.setYY("Yes");
    sent.setDate(new Date());
    myDao.saveOrUpdate(sent); // Insert will be called
} else if(! "Yes".equalsIgnoreCase(sent.getFlag())) {
    sent.setXX("Yes");
    sent.setDate(new Date());
    myDao.saveOrUpdate(sent); // Update will be called
}
1
Jaikrat

これは、主キーの値に基づいて行われます。主キーが未定義の場合、数値の代理キーの値はデフォルトで0になり、saveが実行されます。主キーが入力されると、updateを呼び出します。

1
Olaf