Hibernateのpersist()とsave()の利点は何ですか?


回答:


154

から このフォーラム投稿

persist()明確に定義されています。一時的なインスタンスを永続化します。ただし、識別子の値が永続インスタンスにすぐに割り当てられるとは限りません。割り当てはフラッシュ時に行われる可能性があります。仕様にはそれが記載されていません。これが私が抱えている問題persist()です。

persist()また、トランザクション境界の外で呼び出された場合、INSERTステートメントが実行されないことも保証します。これは、拡張されたセッション/永続コンテキストを使用した長時間の会話で役立ちます。

のような方法 persist()が必要です。

save()同じことを保証するものではありません。識別子を返します。識別子を取得するためにINSERTを実行する必要がある場合(たとえば、「シーケンス」ではなく「アイデンティティ」ジェネレータ)、このINSERTは、内部か外部かに関係なく、すぐに実行されます。トランザクション。これは、拡張されたセッション/持続性コンテキストでの長時間の会話には適していません。


44
同じ投稿からさらに泣き言を追加するには: "残念なことに、5年経った今でも、このスレッドはこの主題に関する唯一の明確な情報源です。Hibernateのドキュメントは冗長ですが、最も重要な使用法以外の情報はありません。クリスチャンの最後の投稿がセッションのjavadocにない理由は、Hibernateのドキュメンテーションミステリーの1つにすぎません。」
kommradHomer

それは、persist()メソッドがエンティティを分離状態にし、save()を接続状態にするということですか?
rekinyz 2015

2
私は最近、1対多の双方向マッピングで保存と永続化の両方を使用しました。保存が子にカスケードされないことがわかりました。つまり、親のみがテーブルに保存/挿入されます。ただし、persistは、1回の呼び出しで親と子の両方を保存するタスクを実行しました。生成されたIDではなく、複合IDを使用しています。
arn-arn 2016

68

ローカルマシンで数回実行するなど、save()とpersist()の良い研究をしました。これまでの説明はすべて混乱しており、正しくありません。徹底的な調査の結果、以下のsave()とpersist()を比較しました。

Save()

  1. 保存後に生成されたIDを返します。そのSerializable戻り値の型。
  2. 変更をトランザクションの外でデータベースに保存します。
  3. 生成したIDを永続化しているエンティティに割り当てます
  4. デタッチされたオブジェクトのSession.save()は、テーブルに新しい行を作成します。

Persist()

  1. 保存後、生成されたIDを返しません。その戻り値の型。
  2. 変更をトランザクション外のデータベースに保存しません。
  3. を割り当てます generated idあなたが持続しているエンティティへ
  4. session.persist() デタッチされたオブジェクトがスローするため PersistentObjectException許可されていないされます。

これらはすべてで試行/テストされていHibernate v4.0.1ます。


Save()とPersist()のポイント3が言及されていますが、実際には同じではありません。Persist()メソッドは、トランザクションの外部でもdbへの変更を保存します。
Ravi.Kumar

2
persistメソッドの値を使用してトランザクションをコミットした後にテストしたときに、DBに保存されません
Laxminarayana Challagonda

それで、#1と#5は2つの本当の違いですか?返されたIDまたは新しい行を作成する必要がある場合は、Save()
user2490003 2018

Save()#3がトランザクション外でどのように可能になるか
vikas singh

24

との違いを記録するために、模擬テストをsave()行いましたpersist()

これらの両方のメソッドのように聞こえるのは、一時エンティティを処理する場合は同じように動作しますが、分離エンティティを処理する場合は異なります。

以下の例vehicleIdでは、生成された値であるPKを持つエンティティとしてEmployeeVehicleを受け取り、vehicleName、そのプロパティの1つでます。

例1:一時オブジェクトの処理

Session session = factory.openSession();
session.beginTransaction();
EmployeeVehicle entity = new EmployeeVehicle();
entity.setVehicleName("Honda");
session.save(entity);
// session.persist(entity);
session.getTransaction().commit();
session.close();

結果:

select nextval ('hibernate_sequence') // This is for vehicle Id generated : 36
insert into Employee_Vehicle ( Vehicle_Name, Vehicle_Id) values ( Honda, 36)

すでに永続化されているオブジェクトを取得して保存した場合も結果は同じです。

EmployeeVehicle entity =  (EmployeeVehicle)session.get(EmployeeVehicle.class, 36);
entity.setVehicleName("Toyota");
session.save(entity);    -------> **instead of session.update(entity);**
// session.persist(entity);

同じことを繰り返します persist(entity)新しいID(たとえば37、ホンダ)でも同じ結果になります。

例2:切り離されたオブジェクトの処理

// Session 1 
// Get the previously saved Vehicle Entity 
Session session = factory.openSession();
session.beginTransaction();
EmployeeVehicle entity = (EmployeeVehicle)session.get(EmployeeVehicle.class, 36);
session.close();

// Session 2
// Here in Session 2 , vehicle entity obtained in previous session is a detached object and now we will try to save / persist it 
// (i) Using Save() to persist a detached object 
Session session2 = factory.openSession();
session2.beginTransaction();
entity.setVehicleName("Toyota");
session2.save(entity);
session2.getTransaction().commit();
session2.close();

結果:前のセッションで取得したid:36の車両が "Toyota"という名前で更新されることを期待している可能性があります。しかし、何が起こるかというと、新しいエンティティがDBに保存され、新しいIDが生成され、名前が「Toyota」になります。

select nextval ('hibernate_sequence')
insert into Employee_Vehicle ( Vehicle_Name, Vehicle_Id) values ( Toyota, 39)

切り離されたエンティティを永続化するための永続化の使用

// (ii) Using Persist()  to persist a detached
// Session 1 
Session session = factory.openSession();
session.beginTransaction();
EmployeeVehicle entity = (EmployeeVehicle)session.get(EmployeeVehicle.class, 36);
session.close();

// Session 2
// Here in Session 2 , vehicle entity obtained in previous session is a detached object and now we will try to save / persist it 
// (i) Using Save() to persist a detached
Session session2 = factory.openSession();
session2.beginTransaction();
entity.setVehicleName("Toyota");
session2.persist(entity);
session2.getTransaction().commit();
session2.close();

結果:

Exception being thrown : detached entity passed to persist

したがって、Transientオブジェクトを扱う場合はsaveを慎重に使用する必要があるため、Save()よりもPersist()を使用する方が常に適切です。

重要な注意:上記の例では、vehicleエンティティのpkが生成された値であるため、save()を使用してデタッチされたエンティティを永続化すると、hibernateは永続化する新しいIDを生成します。ただし、このpkが生成された値ではない場合、キーの違反を示す例外が発生します。


12

この質問には、Hibernateのさまざまな永続化メソッドに関するいくつかの良い答えがあります。質問に直接答えるために、save()を使用すると、トランザクションの状態に関係なく、insertステートメントがすぐに実行されます。挿入されたキーを返すので、次のようなことができます:

long newKey = session.save(myObj);

したがって、永続インスタンスに識別子をすぐに割り当てる必要がある場合は、save()を使用します。

persist()を使用すると、必ずしもすぐにではなく、トランザクションでinsertステートメントが実行されます。これはほとんどの場合に適しています。

トランザクションでシーケンス外で挿入を行う必要がなく、挿入されたキーを返す必要がない場合は、persist()を使用します。


6

以下は、persistメソッドとsaveメソッドの利点を理解するのに役立つ違いです。

  • 保存と永続化の最初の違いは、戻り値のタイプです。永続的なメソッドの戻りの型は無効ですが、保存の戻りの型は
    メソッドのがSerializableオブジェクトです。
  • persist()メソッドは、識別子の値が永続的な状態にすぐに割り当てられることを保証しません。割り当てはフラッシュ時に行われる可能性があります。

  • persist()メソッドは、トランザクション境界の外で呼び出された場合、挿入クエリを実行しません。一方、save()メソッドは識別子を返すため、トランザクションの内部か外部かに関係なく、挿入クエリがすぐに実行されて識別子が取得されます。

  • persistメソッドはトランザクション境界の外で呼び出されます。これは、拡張されたSessionコンテキストとの長時間の会話で役立ちます。一方、saveメソッドは、拡張されたSessionコンテキストとの長時間の会話には適していません。

  • Hibernateのsaveメソッドとpersistメソッドの5番目の違い:保存はJPAでサポートされていますが、saveはHibernateでのみサポートされています。

Hibernateのsaveメソッドとpersistメソッドの違いの投稿から完全な動作例を見ることができます


最初に、「persist()メソッドは、トランザクション境界の外で呼び出された場合、挿入クエリを実行しません」と言います。次に、「persistメソッドはトランザクション境界の外で呼び出されます。これは、拡張されたSessionコンテキストとの長時間の会話に役立ちます。」彼らは矛盾していませんか?分からない。
クマールマニッシュ

@KumarManish persistメソッドの場合、挿入クエリはフラッシュ時に発生します。つまり、長期にわたる会話のベストプラクティスです
David Pham

5

save()-メソッド名が示すように、hibernate save()を使用してエンティティをデータベースに保存できます。トランザクションの外でこのメソッドを呼び出すことができます。トランザクションなしでこれを使用し、エンティティ間のカスケードがある場合、セッションをフラッシュしない限り、プライマリエンティティのみが保存されます。

persist()-Hibernate persistは、save(with transaction)に似ており、エンティティオブジェクトを永続コンテキストに追加するため、それ以降の変更は追跡されます。トランザクションがコミットされる前、またはセッションがフラッシュされる前にオブジェクトのプロパティが変更された場合、それもデータベースに保存されます。また、persist()メソッドはトランザクションの境界内でのみ使用できるため、安全で、カスケードされたオブジェクトを処理します。最後に、persistは何も返さないため、生成された識別子の値を取得するには、永続化されたオブジェクトを使用する必要があります。


5

ここに違いがあります:

  1. 保存する:

    1. オブジェクトがデータベースに保存されると、ID /識別子が返されます。
    2. オブジェクトがデタッチされた後に新しいセッションを開くことにより、オブジェクトが同じことを試みたときにも保存されます。
  2. 持続:

    1. オブジェクトがデータベースに保存されると、voidを返します。
    2. 新しいセッションでデタッチされたオブジェクトを保存しようとすると、PersistentObjectExceptionがスローされます。

スニペットの例を示していただけませんか。それは便利でしょう。
Avikool91

5

基本的なルールはそれを言う:

生成された識別子を持つエンティティの場合:

save():オブジェクトを永続化するだけでなく、エンティティの識別子をすぐに返します。そのため、挿入クエリがすぐに実行されます。

persist():永続オブジェクトを返します。識別子をすぐに返す必要はないため、挿入がすぐに実行されることは保証されません。すぐに挿入が実行される可能性がありますが、保証はされません。クエリがすぐに実行される場合もあれば、セッションのフラッシュ時に実行される場合もあります。

識別子が割り当てられたエンティティの場合:

save():エンティティの識別子をすぐに返します。識別子は、saveを呼び出す前にエンティティに既に割り当てられているため、挿入はすぐには実行されません。セッションのフラッシュ時に発生します。

persist():保存と同じ。また、フラッシュ時にインサートを起動します。

次のように生成された識別子を使用するエンティティがあるとします。

@Entity
@Table(name="USER_DETAILS")
public class UserDetails {
    @Id
    @Column(name = "USER_ID")
    @GeneratedValue(strategy=GenerationType.AUTO)
    private int userId;

    @Column(name = "USER_NAME")
    private String userName;

    public int getUserId() {
        return userId;
    }
    public void setUserId(int userId) {
        this.userId = userId;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
}

保存する() :

    Session session = sessionFactory.openSession();
    session.beginTransaction();
    UserDetails user = new UserDetails();
    user.setUserName("Gaurav");
    session.save(user); // Query is fired immediately as this statement is executed.
    session.getTransaction().commit();
    session.close();

persist():

    Session session = sessionFactory.openSession();
    session.beginTransaction();
    UserDetails user = new UserDetails();
    user.setUserName("Gaurav");
    session.persist(user); // Query is not guaranteed to be fired immediately. It may get fired here.
    session.getTransaction().commit(); // If it not executed in last statement then It is fired here.
    session.close();

ここで、idフィールドにアノテーションが生成されていない、つまりIDが手動で割り当てられることなく、次のように定義された同じエンティティがあるとします。

@Entity
@Table(name="USER_DETAILS")
public class UserDetails {
    @Id
    @Column(name = "USER_ID")
    private int userId;

    @Column(name = "USER_NAME")
    private String userName;

    public int getUserId() {
        return userId;
    }
    public void setUserId(int userId) {
        this.userId = userId;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
}

save()の場合:

Session session = sessionFactory.openSession();
session.beginTransaction();
UserDetails user = new UserDetails();
user.setUserId(1);
user.setUserName("Gaurav");
session.save(user); // Query is not fired here since id for object being referred by user is already available. No query need to be fired to find it. Data for user now available in first level cache but not in db.
session.getTransaction().commit();// Query will be fired at this point and data for user will now also be available in DB
session.close();

persist()の場合:

Session session = sessionFactory.openSession();
session.beginTransaction();
UserDetails user = new UserDetails();
user.setUserId(1);
user.setUserName("Gaurav");
session.persist(user); // Query is not fired here.Object is made persistent. Data for user now available in first level cache but not in db.
session.getTransaction().commit();// Query will be fired at this point and data for user will now also be available in DB
session.close();

上記のケースは、トランザクション内から保存または永続化が呼び出された場合に当てはまりました。

保存と永続化の違いの他のポイントは次のとおりです。

  1. save()はトランザクションの外で呼び出すことができます。割り当てられた識別子が使用されている場合、IDはすでに使用可能であるため、挿入クエリはすぐには実行されません。クエリは、セッションがフラッシュされたときにのみ発生します。

  2. 生成された識別子が使用されている場合、IDを生成する必要があるため、挿入がすぐに実行されます。ただし、保存されるのはプライマリエンティティのみです。エンティティにカスケードされたエンティティがある場合、それらはこの時点ではdbに保存されません。それらは、セッションがフラッシュされるときに保存されます。

  3. persist()がトランザクションの外部にある場合、使用される識別子の種類(生成または割り当て)に関係なく、セッションがフラッシュされたときにのみ挿入が発生します。

  4. 永続オブジェクトに対してsaveが呼び出された場合、エンティティは更新クエリを使用して保存されます。


2

実際には、hibernate save()メソッドとpersist()メソッドの違いは、使用しているジェネレータークラスによって異なります。
ジェネレータークラスが割り当てられている場合、save()メソッドとpersist()メソッドの間に違いはありません。ジェネレーターは「割り当てられた」という意味なので、プログラマーとして、データベースに保存する主キーの値を指定する必要があります[このジェネレーターのコンセプトを知っているとよい]割り当てられたジェネレータークラス以外の場合、ジェネレータークラス名がIncrement hibernate自体がプライマリキーID値をデータベースの権利に割り当てます[割り当てられたジェネレーター以外では、hibernateはプライマリキーID値を覚えておくためにのみ使用されます]。この場合、save()またはpersist()メソッドを呼び出すと、通常、データベースにレコードを挿入します。
しかし、ここで重要なのは、save()メソッドがhibernateによって生成されたその主キーID値を返すことができ、それを
long s = session.save(k);で確認できることです。
これと同じ場合、persist()はクライアントに値を返しません。戻り型はvoidです。
また、persist()は、トランザクション境界の外で呼び出された場合にINSERTステートメントを実行しないことも保証します。
一方、save()では、トランザクションの内部か外部かに関係なく、INSERTはすぐに発生します。


1

IDの「ジェネレータ」タイプに基づいて完全に応答し、エンティティを格納します。ジェネレーターの値が「割り当てられている」場合、これはIDを提供していることを意味します。その後、保存または永続化のために休止状態での違いはありません。あなたは好きな方法で行くことができます。値が「割り当て」られておらず、save()を使用している場合、save()オペレーションからの戻りとしてIDを取得します。

別のチェックは、トランザクションの制限外で操作を実行しているかどうかです。なぜならば、persist()はJPAに属し、hibernateの場合はsave()に属します。したがって、トランザクション境界の外でpersist()を使用すると、そうすることができず、永続性に関連する例外がスローされます。一方、save()ではそのような制限はなく、トランザクションの制限外でsave()を使用してDBトランザクションを実行できます。

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