Quel est l'avantage de persist () par rapport à save () dans Hibernate?

Réponses:

154

De ce message de forum

persist()est bien défini. Cela rend une instance transitoire persistante. Cependant, cela ne garantit pas que la valeur de l'identificateur sera affectée immédiatement à l'instance persistante, l'affectation peut se produire au moment du vidage. La spécification ne dit pas cela, c'est le problème avec lequel j'ai persist().

persist()garantit également qu'il n'exécutera pas une instruction INSERT si elle est appelée en dehors des limites de la transaction. Ceci est utile dans les conversations de longue durée avec un contexte de session / persistance étendu.

Une méthode comme celle-ci persist()est requise.

save()ne garantit pas la même chose, il renvoie un identifiant, et si un INSERT doit être exécuté pour obtenir l'identifiant (par exemple générateur "d'identité", pas "séquence"), cet INSERT se produit immédiatement, peu importe si vous êtes à l'intérieur ou à l'extérieur de une transaction. Ce n'est pas bon dans une conversation de longue durée avec un contexte de session / persistance étendu.

Bala R
la source
44
pour en ajouter plus à partir du même message, pour pleurnicher: "Malheureusement, 5 ans plus tard, ce fil reste toujours la seule source claire d'informations sur ce sujet. La documentation Hibernate, bien que verbeuse, est vide de toutes les informations d'utilisation sauf les plus triviales. Pourquoi le dernier message de Christian n'est pas dans la Session javadoc est juste un autre mystère de documentation Hibernate. "
kommradHomer
voulez-vous dire que la méthode persist () rendra l'entité à l'état détaché et save () à l'état attaché?
rekinyz le
2
J'ai récemment utilisé à la fois enregistrer et persister dans un mappage bidirectionnel un-à-plusieurs. J'ai découvert que save ne cascade pas à l'enfant, c'est-à-dire que seul le parent est enregistré / inséré dans la table. Cependant, persist a accompli la tâche de sauvegarder le parent et l'enfant en un seul appel. J'utilise un ID composite et non un ID généré.
arn-arn
68

J'ai fait de bonnes recherches sur save () vs persist (), notamment en l'exécutant plusieurs fois sur ma machine locale. Toutes les explications précédentes prêtent à confusion et ne sont pas correctes. J'ai comparé le save () et le persist () ci-dessous après une recherche approfondie.

Save()

  1. Renvoie l'ID généré après l'enregistrement. Son Serializabletype de retour.
  2. enregistrez les modifications apportées à la base de données en dehors de la transaction.
  3. Attribue l'ID généré à l'entité que vous persistez
  4. Session.save () pour un objet détaché créera une nouvelle ligne dans le tableau.

Persist()

  1. Ne renvoie pas l'ID généré après l'enregistrement. Son type de retour nul.
  2. N'enregistre pas les modifications apportées à la base de données en dehors de la transaction.
  3. Attribue le generated idà l'entité que vous persistez
  4. session.persist()car un objet détaché lancera PersistentObjectExceptioncar ce n'est pas autorisé.

Tous ceux-ci sont essayés / testés sur Hibernate v4.0.1.

Zeus
la source
Le point 3 pour Save () et Persist () sont mentionnés mais ils ne sont pas réellement les mêmes. La méthode Persist () enregistre également les modifications apportées à db en dehors de la transaction.
Ravi.Kumar
2
lorsque j'ai testé après avoir
validé
Donc, les numéros 1 et 5 sont la vraie différence entre les deux? Si vous avez besoin d'un identifiant renvoyé ou d'une nouvelle ligne créée, utilisez Save()?
user2490003
Comment Save () # 3 est possible en dehors de la transaction
Vikas Singh
24

J'ai fait quelques tests simulés pour enregistrer la différence entre save()et persist().

On dirait que ces deux méthodes se comportent de la même manière lorsqu'il s'agit d'une entité transitoire, mais diffèrent lorsqu'il s'agit d'une entité détachée.

Pour l'exemple ci-dessous, prenez EmployeeVehicle comme une entité avec PK comme vehicleIdvaleur générée et vehicleNamecomme l'une de ses propriétés.

Exemple 1: gestion d'un objet transitoire

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

Résultat:

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

Notez que le résultat est le même lorsque vous obtenez un objet déjà persistant et que vous l'enregistrez

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

Répétez la même chose en utilisant persist(entity)et le résultat sera le même avec le nouvel Id (disons 37, honda);

Exemple 2: gestion d'un objet détaché

// 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();

Résultat: vous vous attendez peut-être à ce que le véhicule avec l'ID: 36 obtenu lors de la session précédente soit mis à jour avec le nom «Toyota». Mais ce qui se passe, c'est qu'une nouvelle entité est enregistrée dans la base de données avec un nouvel identifiant généré pour et un nom comme "Toyota"

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

Utilisation de persist pour conserver l'entité détachée

// (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();

Résultat:

Exception being thrown : detached entity passed to persist

Donc, il est toujours préférable d'utiliser Persist () plutôt que Save () car save doit être utilisé avec précaution lors du traitement d'un objet Transient.

Remarque importante: Dans l'exemple ci-dessus, le pk de l'entité de véhicule est une valeur générée, donc lorsque vous utilisez save () pour conserver une entité détachée, hibernate génère un nouvel identifiant à conserver. Cependant, si ce pk n'est pas une valeur générée, il en résulte une exception indiquant la clé violée.

Deivanayagam Senthil
la source
13

Cette question a de bonnes réponses sur les différentes méthodes de persistance dans Hibernate. Pour répondre directement à votre question, avec save () l'instruction d'insertion est exécutée immédiatement quel que soit l'état de la transaction. Il renvoie la clé insérée afin que vous puissiez faire quelque chose comme ceci:

long newKey = session.save(myObj);

Utilisez donc save () si vous avez besoin d'un identifiant attribué immédiatement à l'instance persistante.

Avec persist (), l'instruction insert est exécutée dans une transaction, pas nécessairement immédiatement. Ceci est préférable dans la plupart des cas.

Utilisez persist () si vous n'avez pas besoin que l'insertion se produise hors séquence avec la transaction et que vous n'avez pas besoin de renvoyer la clé insérée.

CFL_Jeff
la source
6

Voici les différences qui peuvent vous aider à comprendre les avantages des méthodes persist et save:

  • La première différence entre save et persist est leur type de retour. Le type de retour de la méthode persist est void tandis que le type de retour de la
    méthode de sauvegarde est un objet sérialisable.
  • La méthode persist () ne garantit pas que la valeur de l'identificateur sera immédiatement affectée à l'état persistant, l'affectation peut se produire au moment du vidage.

  • La méthode persist () n'exécutera pas de requête d'insertion si elle est appelée en dehors des limites de la transaction. Alors que, la méthode save () retourne un identifiant pour qu'une requête d'insertion soit exécutée immédiatement pour obtenir l'identifiant, qu'il soit à l'intérieur ou à l'extérieur d'une transaction.

  • La méthode persist est appelée en dehors des limites des transactions, elle est utile dans les conversations de longue durée avec un contexte de session étendu. D'autre part, la méthode de sauvegarde n'est pas bonne dans une conversation de longue durée avec un contexte de session étendu.

  • Cinquième différence entre la méthode save et persist dans Hibernate: persist est pris en charge par JPA, tandis que save n'est pris en charge que par Hibernate.

Vous pouvez voir l'exemple de travail complet de l'article Différence entre la méthode save et persist dans Hibernate

David Pham
la source
Vous dites d'abord "La méthode persist () n'exécutera pas de requête d'insertion si elle est appelée en dehors des limites de transaction". Ensuite, vous dites "La méthode persist est appelée en dehors des limites de transaction, elle est utile dans les conversations de longue durée avec un contexte de session étendu." Ne sont-ils pas contradictoires? Je ne comprends pas.
Kumar Manish
@KumarManish Dans le cas de la méthode persist, une requête d'insertion se produit au moment du vidage. C'est donc une des meilleures pratiques dans les conversations de longue durée
David Pham
5

save () - Comme le nom de la méthode l'indique, hibernate save () peut être utilisé pour enregistrer l'entité dans la base de données. Nous pouvons invoquer cette méthode en dehors d'une transaction. Si nous utilisons cela sans transaction et que nous avons une cascade entre les entités, alors seule l'entité principale est enregistrée à moins que nous ne vidions la session.

persist () - Hibernate persist est similaire à save (avec transaction) et ajoute l'objet entité au contexte persistant, de sorte que toutes les modifications ultérieures sont suivies. Si les propriétés de l'objet sont modifiées avant la validation de la transaction ou le vidage de la session, il sera également enregistré dans la base de données. De plus, nous pouvons utiliser la méthode persist () uniquement dans les limites d'une transaction, elle est donc sûre et prend en charge tous les objets en cascade. Enfin, persist ne renvoie rien, nous devons donc utiliser l'objet persistant pour obtenir la valeur d'identificateur générée.

Rohit Goyal
la source
5

Voici la différence:

  1. enregistrer:

    1. renverra l'id / identifiant lorsque l'objet est enregistré dans la base de données.
    2. enregistre également lorsque l'objet est tenté de faire de même en ouvrant une nouvelle session après son détachement.
  2. Persister:

    1. retournera void lorsque l'objet est enregistré dans la base de données.
    2. lancera une exception PersistentObjectException lors de la tentative d'enregistrement de l'objet détaché via une nouvelle session.
Mohammed Amen
la source
Pouvez-vous s'il vous plaît montrer un exemple avec un extrait. Ce serait utile.
Avikool91
5

La règle de base dit que:

Pour les entités avec un identifiant généré:

save (): Il renvoie immédiatement l'identifiant d'une entité en plus de rendre l'objet persistant. Ainsi, une requête d'insertion est déclenchée immédiatement.

persist (): il renvoie l'objet persistant. Il n'a aucune obligation de renvoyer l'identifiant immédiatement, donc il ne garantit pas que l'insert sera déclenché immédiatement. Il peut déclencher un insert immédiatement mais ce n'est pas garanti. Dans certains cas, la requête peut être déclenchée immédiatement tandis que dans d'autres, elle peut être déclenchée au moment du vidage de la session.

Pour les entités avec un identifiant attribué:

save (): Il renvoie immédiatement l'identifiant d'une entité. Comme l'identifiant est déjà attribué à l'entité avant d'appeler save, l'insertion n'est pas déclenchée immédiatement. Il est déclenché au moment du vidage de la session.

persist (): identique à save. Il déclenche également l'insert au moment du rinçage.

Supposons que nous ayons une entité qui utilise un identifiant généré comme suit:

@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;
    }
}

enregistrer() :

    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();

Supposons maintenant que nous ayons la même entité définie comme suit sans que le champ id n'ait généré une annotation, c'est-à-dire que l'ID sera attribué manuellement.

@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;
    }
}

pour 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();

pour 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();

Les cas ci-dessus étaient vrais lorsque la sauvegarde ou la persistance étaient appelées à partir d'une transaction.

Les autres points de différence entre save et persist sont:

  1. save () peut être appelé en dehors d'une transaction. Si un identifiant attribué est utilisé, puisque id est déjà disponible, aucune requête d'insertion n'est immédiatement déclenchée. La requête n'est déclenchée que lorsque la session est purgée.

  2. Si l'identifiant généré est utilisé, puis comme id doit être généré, l'insertion est immédiatement déclenchée. Mais cela ne sauvegarde que l'entité principale. Si l'entité a des entités en cascade, celles-ci ne seront pas enregistrées dans la base de données à ce stade. Ils seront enregistrés lorsque la session sera purgée.

  3. Si persist () est en dehors d'une transaction, l'insertion n'est déclenchée que lorsque la session est purgée, quel que soit le type d'identifiant (généré ou attribué) utilisé.

  4. Si save est appelé sur un objet persistant, l'entité est enregistrée à l'aide de la requête de mise à jour.

Gaurav Kumar
la source
2

En fait, la différence entre les méthodes hibernate save () et persist () dépend de la classe de générateur que nous utilisons.
Si notre classe de générateur est assignée, alors il n'y a aucune différence entre les méthodes save () et persist (). Parce que le générateur «assigné» signifie, en tant que programmeur, nous devons donner la valeur de la clé primaire à sauvegarder dans la base de données. hibernate lui-même attribuera la valeur de l'identifiant de la clé primaire dans le droit de la base de données [autre que le générateur attribué, hibernate utilisé uniquement pour prendre soin de la valeur de l'identifiant de la clé primaire, rappelez-vous], donc dans ce cas, si nous appelons la méthode save () ou persist (), alors il insérera normalement l'enregistrement dans la base de données.
Mais ici, le fait est que la méthode save () peut renvoyer cette valeur d'identifiant de clé primaire qui est générée par hibernate et nous pouvons la voir par
long s = session.save (k);
Dans ce même cas, persist () ne rendra jamais aucune valeur au client, retourne le type void.
persist () garantit également qu'il n'exécutera pas une instruction INSERT s'il est appelé en dehors des limites de la transaction.
alors que dans save (), INSERT se produit immédiatement, peu importe si vous êtes à l'intérieur ou à l'extérieur d'une transaction.

Hari Krishna
la source
1

Il a répondu complètement sur la base du type "générateur" dans l'ID tout en stockant n'importe quelle entité. Si la valeur du générateur est «affectée», cela signifie que vous fournissez l'ID. Ensuite, il ne fait aucune différence en veille prolongée pour enregistrer ou persister. Vous pouvez utiliser n'importe quelle méthode que vous souhaitez. Si la valeur n'est pas "assignée" et que vous utilisez save (), vous obtiendrez l'ID en retour de l'opération save ().

Une autre vérification est de savoir si vous effectuez l'opération en dehors de la limite de transaction ou non. Parce que persist () appartient à JPA tandis que save () pour la mise en veille prolongée. Donc, utiliser persist () en dehors des limites de transaction ne permettra pas de le faire et lèvera une exception liée à persistant. tandis qu'avec save () aucune restriction de ce type et on peut aller avec DB transaction via save () en dehors de la limite de transaction.

Neeraj
la source