Quelqu'un peut-il me dire quel est l'avantage de persist()
vs save()
dans Hibernate?
persist()
est bien défini. Cela rend une instance transitoire persistante. Cependant, cela ne garantit pas que la valeur de l'identifiant sera immédiatement assignée à l'instance persistante, l'affectation peut avoir lieu au moment du vidage. La spécification ne dit pas cela, c'est le problème que j'ai avecpersist()
.
persist()
garantit également qu'il n'exécutera pas d'instruction INSERT s'il est appelé 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
persist()
est requise.
save()
ne garantit pas la même chose, il retourne un identifiant, et si un INSERT doit être exécuté pour obtenir l'identifiant (par exemple, le générateur "identité" et non "séquence"), cet INSERT se produit immédiatement, peu importe si vous sont à l'intérieur ou à l'extérieur d'une transaction. Ce n'est pas bon dans une conversation longue avec un contexte de session/persistance étendu.
J'ai fait de bonnes recherches sur save () vs persist (), y compris en l'exécutant plusieurs fois sur ma machine locale. Toutes les explications précédentes sont déroutantes et ne sont pas correctes. J'ai comparé les méthodes save () et persist () ci-dessous après une recherche approfondie.
Save()
Serializable
.Persist()
generated id
à l'entité que vous persistezsession.persist()
pour un objet détaché jettera PersistentObjectException
car ce n'est pas autorisé.Tous ces éléments sont essayés/testés sur Hibernate v4.0.1
.
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 avec une entité transitoire, mais diffèrent s’agissant d’une entité séparée.
Pour l'exemple ci-dessous, prenons EmployeeVehicle en tant qu'entité avec PK comme vehicleId
qui est une valeur générée et vehicleName
comme l'une de ses propriétés.
Exemple 1: Traitement 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 identique lorsque vous récupérez un objet déjà persistant et le sauvegardez.
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 avec persist(entity)
pour obtenir le même identifiant (par exemple 37, honda);
Exemple 2: Traiter avec 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 produit, c’est qu’une nouvelle entité est enregistrée dans la base de données avec le nouvel ID généré pour et Nom en tant que "Toyota".
select nextval ('hibernate_sequence')
insert into Employee_Vehicle ( Vehicle_Name, Vehicle_Id) values ( Toyota, 39)
Utilisation de persist pour persister entité séparé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
Il est donc toujours préférable d’utiliser Persist () plutôt que Save (), car save doit être utilisé avec précaution lorsqu’il s’agit d’un objet Transitoire.
Remarque importante: dans l'exemple ci-dessus, le pk de l'entité véhicule est une valeur générée. Ainsi, lorsque vous utilisez save () pour conserver une entité détachée, hibernate génère un nouvel ID à conserver. Cependant, si ce pk n'est pas une valeur générée, il en résulte une exception indiquant que la clé a été violée.
Cette question a de bonnes réponses à propos des différentes méthodes de persistance dans Hibernate. Pour répondre directement à votre question, avec save (), la commande insert est exécutée immédiatement quel que soit l'état de la transaction. Il retourne la clé insérée pour 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 d'insertion 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 la clé insérée ne soit pas renvoyée.
Voici les différences qui vous aident à tirer parti de la méthode persist et save:
La méthode persist () ne garantit pas que la valeur de l'identifiant sera immédiatement affectée à l'état persistant, l'affectation peut avoir lieu au moment de la purge.
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 () renvoie un identifiant afin 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 de la transaction. Elle est utile dans les conversations de longue durée avec un contexte de session étendu. Par ailleurs, la méthode de sauvegarde n’est pas efficace dans une conversation de longue durée avec un contexte de session étendu.
Cinquième différence entre les méthodes save et persist dans Hibernate: persist est pris en charge par JPA, tandis que save est uniquement pris en charge par Hibernate.
Vous pouvez voir l’exemple complet complet à partir de la publication Différence entre les méthodes save et persist dans Hibernate
save () - Comme le nom de la méthode le suggère, hibernate save () peut être utilisé pour enregistrer une entité dans une base de données. Nous pouvons invoquer cette méthode en dehors d'une transaction. Si nous l'utilisons sans transaction et que nous avons des cascades entre entités, seule l'entité principale est enregistrée, à moins que la session ne soit vidée.
persist () - Hibernate persist est similaire à save (avec transaction) et ajoute l'objet entité au contexte persistant pour que toutes les modifications ultérieures soient 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 ne pouvons utiliser la méthode persist () que 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.
Voici la différence:
enregistrer:
Persister:
En fait, la différence entre les méthodes hibernate save () et persist () dépend de la classe du générateur que nous utilisons.
Si notre classe de générateur est assignée, il n'y a pas de différence entre les méthodes save () et persist (). Parce que générateur 'assigné' signifie, en tant que programmeur, nous devons donner la valeur de clé primaire à enregistrer dans la base de données à droite [espérons que vous connaissez ce concept de générateurs] Dans le cas d'une classe de générateur autre qu'attribuée, supposons si notre nom de classe de générateur est Incrément signifie hibernate it self assignera la valeur de la clé primaire id dans la base de données à droite [autre que le générateur assigné, hibernate ne sert que pour prendre soin de la valeur de la clé primaire se souvenir], donc dans ce cas si nous appelons la méthode save () ou persist () il insérera normalement l'enregistrement dans la base de données
Mais écoutez, la méthode save () peut renvoyer la valeur de la clé primaire id générée par hibernate et que nous pouvons voir par
long s = session.save (k);
Dans ce même cas, persist () ne restituera jamais aucune valeur au client, retournera void.
persist () garantit également qu'il n'exécutera pas d'instruction INSERT s'il est appelé en dehors des limites de la transaction.
où as Save () INSERT se produit immédiatement, peu importe si vous êtes à l'intérieur ou à l'extérieur d'une transaction.
La règle de base dit que:
Pour les entités avec l'identifiant généré:
save (): Il retourne immédiatement l'identifiant d'une entité en plus de rendre l'objet persistant. Donc, une requête d'insertion est déclenchée immédiatement.
persist (): renvoie l'objet persistant. Il n'a aucune obligation de renvoyer l'identificateur immédiatement, il ne garantit donc pas que l'insert sera déclenché immédiatement. Il peut déclencher un insert immédiatement, mais cela n’est pas garanti. Dans certains cas, la requête peut être déclenchée immédiatement alors que dans d'autres, elle peut l'être au moment du vidage de session.
Pour les entités auxquelles un identifiant est attribué:
save (): Il retourne immédiatement l'identifiant d'une entité. Puisque l'identifiant est déjà attribué à l'entité avant l'appel de la sauvegarde, l'insertion n'est pas déclenchée immédiatement. Il est déclenché au moment de la session.
persist (): identique à save. Il fait également feu insérer au moment de la chasse.
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.save(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 la même entité soit définie comme suit sans que le champ id ait généré l'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 persister ():
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 depuis une transaction.
Les autres points de différence entre save et persist sont:
save () peut être appelé en dehors d'une transaction. Si l'identifiant attribué est utilisé, alors que id est déjà disponible, aucune requête d'insertion n'est immédiatement déclenchée. La requête est uniquement déclenchée lorsque la session est vidée.
Si l'identifiant généré est utilisé, puis, puisque l'identifiant doit être généré, l'insertion est immédiatement déclenchée. Mais cela n'enregistre 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 sauvegardés lorsque la session sera vidée.
Si persist () est en dehors d'une transaction, l'insertion est déclenchée uniquement lorsque la session est vidé, quel que soit le type d'identificateur utilisé (généré ou attribué).
Si save est appelé sur un objet persistant, l'entité est enregistrée à l'aide de la requête de mise à jour.
Il a complètement répondu sur la base du type "générateur" en identifiant tout en stockant une entité. Si la valeur du générateur est "assignée", cela signifie que vous fournissez l'ID. Ensuite, il ne fait aucune différence en veille prolongée pour la sauvegarde ou la persistance. Vous pouvez aller avec n'importe quelle méthode que vous voulez. Si la valeur n'est pas "assignée" et que vous utilisez save (), vous obtiendrez l'ID en tant que résultat de l'opération save ().
Une autre vérification est si vous effectuez l'opération en dehors de la limite de transaction ou non. Parce que persist () appartient à JPA while save () pour hibernate. Donc, utiliser persist () en dehors des limites de la transaction ne le permettra pas et lèvera une exception liée à persistante. while with save () pas de restriction de ce type et on peut utiliser une transaction de base de données via save () en dehors de la limite de transaction.