Session Hibernate est l’interface entre l’application Java et le framework Hibernate. Aujourd’hui, nous examinerons les méthodes importantes de Session pour sauvegarder et mettre à jour les données dans les tables – save, saveOrUpdate, persist, update et merge.
Session Hibernate
Enregistrer la Session Hibernate
Comme son nom l’indique, hibernate save() peut être utilisé pour enregistrer une entité dans la base de données. Nous pouvons invoquer cette méthode en dehors d’une transaction, c’est pourquoi je n’aime pas cette méthode pour sauvegarder des données. Si nous utilisons cela sans transaction et que nous avons une cascade entre les entités, alors seule l’entité principale est sauvegardée à moins que nous ne vidions la session. À des fins de test, nous avons deux entités – Employee
et Address
.
package com.journaldev.hibernate.model;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import org.hibernate.annotations.Cascade;
@Entity
@Table(name = "EMPLOYEE")
@Access(value=AccessType.FIELD)
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "emp_id")
private long id;
@Column(name = "emp_name")
private String name;
@Column(name = "emp_salary")
private double salary;
@OneToOne(mappedBy = "employee")
@Cascade(value = org.hibernate.annotations.CascadeType.ALL)
private Address address;
// Méthodes getter et setter
@Override
public String toString() {
return "Id= " + id + ", Name= " + name + ", Salary= " + salary
+ ", {Address= " + address + "}";
}
}
package com.journaldev.hibernate.model;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
@Entity
@Table(name = "ADDRESS")
@Access(value=AccessType.FIELD)
public class Address {
@Id
@Column(name = "emp_id", unique = true, nullable = false)
@GeneratedValue(generator = "gen")
@GenericGenerator(name = "gen", strategy = "foreign", parameters = { @Parameter(name = "property", value = "employee") })
private long id;
@Column(name = "address_line1")
private String addressLine1;
@Column(name = "zipcode")
private String zipcode;
@Column(name = "city")
private String city;
@OneToOne
@PrimaryKeyJoinColumn
private Employee employee;
// Méthodes getter et setter
@Override
public String toString() {
return "AddressLine1= " + addressLine1 + ", City=" + city
+ ", Zipcode=" + zipcode;
}
}
Voici un programme Hibernate simple où nous invoquons la méthode save()
dans différents cas.
package com.journaldev.hibernate.main;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.journaldev.hibernate.model.Address;
import com.journaldev.hibernate.model.Employee;
import com.journaldev.hibernate.util.HibernateUtil;
public class HibernateSaveExample {
public static void main(String[] args) {
// Travail préparatoire
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
//exemple de sauvegarde - sans transaction
Session session = sessionFactory.openSession();
Employee emp = getTestEmployee();
long id = (Long) session.save(emp);
System.out.println("1. Employee save called without transaction, id="+id);
session.flush(); //address will not get saved without this
System.out.println("*****");
//exemple de sauvegarde - avec transaction
Transaction tx1 = session.beginTransaction();
Session session1 = sessionFactory.openSession();
Employee emp1 = getTestEmployee();
long id1 = (Long) session1.save(emp1);
System.out.println("2. Employee save called with transaction, id="+id1);
System.out.println("3. Before committing save transaction");
tx1.commit();
System.out.println("4. After committing save transaction");
System.out.println("*****");
//exemple de sauvegarde - ligne existante dans la table
Session session6 = sessionFactory.openSession();
Transaction tx6 = session6.beginTransaction();
Employee emp6 = (Employee) session6.load(Employee.class, new Long(20));
//mettre à jour certaines données
System.out.println("Employee Details="+emp6);
emp6.setName("New Name");
emp6.getAddress().setCity("New City");
long id6 = (Long) session6.save(emp6);
emp6.setName("New Name1"); // will get updated in database
System.out.println("5. Employee save called with transaction, id="+id6);
System.out.println("6. Before committing save transaction");
tx6.commit();
System.out.println("7. After committing save transaction");
System.out.println("*****");
// Fermer les ressources
sessionFactory.close();
}
public static Employee getTestEmployee() {
Employee emp = new Employee();
Address add = new Address();
emp.setName("Test Emp");
emp.setSalary(1000);
add.setAddressLine1("Test address1");
add.setCity("Test City");
add.setZipcode("12121");
emp.setAddress(add);
add.setEmployee(emp);
return emp;
}
}
Lorsque nous exécutons le programme ci-dessus, il produit la sortie suivante.
Hibernate: insert into EMPLOYEE (emp_name, emp_salary) values (?, ?)
1. Employee save called without transaction, id=149
Hibernate: insert into ADDRESS (address_line1, city, zipcode, emp_id) values (?, ?, ?, ?)
*****
Hibernate: insert into EMPLOYEE (emp_name, emp_salary) values (?, ?)
2. Employee save called with transaction, id=150
3. Before committing save transaction
Hibernate: insert into ADDRESS (address_line1, city, zipcode, emp_id) values (?, ?, ?, ?)
4. After committing save transaction
*****
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
Employee Details=Id= 20, Name= Kumar1, Salary= 1000.0, {Address= AddressLine1= Test address1, City=Blr, Zipcode=12121}
5. Employee save called with transaction, id=20
6. Before committing save transaction
Hibernate: update EMPLOYEE set emp_name=?, emp_salary=? where emp_id=?
Hibernate: update ADDRESS set address_line1=?, city=?, zipcode=? where emp_id=?
7. After committing save transaction
*****
Quelques points importants que nous pouvons confirmer à partir de la sortie ci-dessus sont :
- Nous devrions éviter de sauvegarder en dehors de la limite de la transaction, sinon les entités mappées ne seront pas sauvegardées, entraînant une incohérence des données. Il est très courant d’oublier de vider la session car elle ne lance aucune exception ni avertissement.
- La méthode save de Hibernate renvoie immédiatement l’identifiant généré, cela est possible car l’objet principal est sauvegardé dès que la méthode save est invoquée.
- Si d’autres objets sont mappés à partir de l’objet principal, ils sont sauvegardés au moment de la validation de la transaction ou lorsque nous vidons la session.
- Pour les objets qui sont en état persistant, save met à jour les données à travers une requête de mise à jour. Remarquez que cela se produit lorsque la transaction est validée. S’il n’y a pas de changements dans l’objet, aucune requête ne sera exécutée. Si vous exécutez le programme ci-dessus plusieurs fois, vous remarquerez que les requêtes de mise à jour ne sont pas exécutées la fois suivante car il n’y a pas de changement dans les valeurs des colonnes.
- Hibernate enregistre l’objet entité avec le contexte persistant, si vous mettez à jour les propriétés de l’objet après l’appel save mais avant la validation de la transaction, il sera enregistré dans la base de données.
Persistez avec Hibernate
La persistance avec Hibernate est similaire à la méthode save (avec transaction) et elle 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 que la transaction ne soit validée ou que la session ne soit vidée, elles seront également enregistrées dans la base de données. La deuxième différence est que nous pouvons utiliser la méthode persist()
uniquement à l’intérieur des limites d’une transaction, ce qui la rend sûre et prend en charge tout objet en cascade. Enfin, persist ne renvoie rien, nous devons donc utiliser l’objet persisté pour obtenir la valeur de l’identifiant généré. Regardons Hibernate persist avec un programme simple.
package com.journaldev.hibernate.main;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.journaldev.hibernate.model.Employee;
import com.journaldev.hibernate.util.HibernateUtil;
public class HibernatePersistExample {
public static void main(String[] args) {
// Préparation
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
// Exemple de persistance - avec transaction
Session session2 = sessionFactory.openSession();
Transaction tx2 = session2.beginTransaction();
Employee emp2 = HibernateSaveExample.getTestEmployee();
session2.persist(emp2);
System.out.println("Persist called");
emp2.setName("Kumar"); // will be updated in database too
System.out.println("Employee Name updated");
System.out.println("8. Employee persist called with transaction, id="+emp2.getId()+", address id="+emp2.getAddress().getId());
tx2.commit();
System.out.println("*****");
// Fermeture des ressources
sessionFactory.close();
}
}
La sortie produite par le code ci-dessus est :
Hibernate: insert into EMPLOYEE (emp_name, emp_salary) values (?, ?)
8. Employee persist called with transaction, id=158, address id=158
Hibernate: insert into ADDRESS (address_line1, city, zipcode, emp_id) values (?, ?, ?, ?)
Hibernate: update EMPLOYEE set emp_name=?, emp_salary=? where emp_id=?
*****
Remarquez que le premier objet employé est inséré, puis au moment de la validation de la transaction, une requête de mise à jour est exécutée pour mettre à jour la valeur du nom. De plus, l’adresse de l’objet mappé est enregistrée dans la base de données.
Enregistrer ou mettre à jour avec Hibernate
Hibernate saveOrUpdate donne lieu à des requêtes d’insertion ou de mise à jour en fonction des données fournies. Si les données sont présentes dans la base de données, une requête de mise à jour est exécutée. Nous pouvons utiliser saveOrUpdate()
sans transaction également, mais vous rencontrerez à nouveau des problèmes si les objets mappés ne sont pas enregistrés si la session n’est pas vidée. Hibernate saveOrUpdate ajoute l’objet entité au contexte persistant et suit tout changement ultérieur. Tout changement ultérieur est enregistré au moment de la validation de la transaction, comme persist.
package com.journaldev.hibernate.main;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.journaldev.hibernate.model.Employee;
import com.journaldev.hibernate.util.HibernateUtil;
public class HibernateSaveOrUpdateExample {
public static void main(String[] args) {
// Préparation
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
// Exemple de saveOrUpdate - sans transaction
Session session5 = sessionFactory.openSession();
Employee emp5 = HibernateSaveExample.getTestEmployee();
session5.saveOrUpdate(emp5);
System.out.println("*****");
// Exemple de saveOrUpdate - avec transaction
Session session3 = sessionFactory.openSession();
Transaction tx3 = session3.beginTransaction();
Employee emp3 = HibernateSaveExample.getTestEmployee();
session3.saveOrUpdate(emp3);
emp3.setName("Kumar"); //will be saved into DB
System.out.println("9. Before committing saveOrUpdate transaction. Id="+emp3.getId());
tx3.commit();
System.out.println("10. After committing saveOrUpdate transaction");
System.out.println("*****");
Transaction tx4 = session3.beginTransaction();
emp3.setName("Updated Test Name"); //Name changed
emp3.getAddress().setCity("Updated City");
session3.saveOrUpdate(emp3);
emp3.setName("Kumar"); //again changed to previous value, so no Employee update
System.out.println("11. Before committing saveOrUpdate transaction. Id="+emp3.getId());
tx4.commit();
System.out.println("12. After committing saveOrUpdate transaction");
System.out.println("*****");
// Fermeture des ressources
sessionFactory.close();
}
}
Le programme ci-dessus produit la sortie suivante.
Hibernate: insert into EMPLOYEE (emp_name, emp_salary) values (?, ?)
*****
Hibernate: insert into EMPLOYEE (emp_name, emp_salary) values (?, ?)
9. Before committing saveOrUpdate transaction. Id=166
Hibernate: insert into ADDRESS (address_line1, city, zipcode, emp_id) values (?, ?, ?, ?)
Hibernate: update EMPLOYEE set emp_name=?, emp_salary=? where emp_id=?
10. After committing saveOrUpdate transaction
*****
11. Before committing saveOrUpdate transaction. Id=166
Hibernate: update ADDRESS set address_line1=?, city=?, zipcode=? where emp_id=?
12. After committing saveOrUpdate transaction
*****
Remarquez que sans transaction, seul l’employé est enregistré et les informations d’adresse sont perdues. Avec la transaction, l’objet employé est suivi pour tout changement, c’est pourquoi lors du dernier appel, il n’y a pas de mise à jour dans la table des employés même si la valeur a été modifiée entre-temps, la valeur finale reste la même.
Mise à jour de Hibernate
Mise à jour de Hibernate devrait être utilisée lorsque nous savons que nous ne mettons à jour que les informations de l’entité. Cette opération ajoute l’objet entité au contexte persistant et les changements ultérieurs sont suivis et enregistrés lorsque la transaction est validée. Vérifions ce comportement avec un programme simple.
package com.journaldev.hibernate.main;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.journaldev.hibernate.model.Employee;
import com.journaldev.hibernate.util.HibernateUtil;
public class HibernateUpdateExample {
public static void main(String[] args) {
// Travail de préparation
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Employee emp = (Employee) session.load(Employee.class, new Long(101));
System.out.println("Employee object loaded. " + emp);
tx.commit();
// exemple de mise à jour
emp.setName("Updated name");
emp.getAddress().setCity("Bangalore");
Transaction tx7 = session.beginTransaction();
session.update(emp);
emp.setName("Final updated name");
System.out.println("13. Before committing update transaction");
tx7.commit();
System.out.println("14. After committing update transaction");
// Fermer les ressources
sessionFactory.close();
}
}
Lorsque nous exécutons le programme ci-dessus pour la première fois, nous obtenons la sortie suivante.
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
Employee object loaded. Id= 101, Name= Test Emp, Salary= 1000.0, {Address= AddressLine1= Test address1, City=Test City, Zipcode=12121}
13. Before committing update transaction
Hibernate: update EMPLOYEE set emp_name=?, emp_salary=? where emp_id=?
Hibernate: update ADDRESS set address_line1=?, city=?, zipcode=? where emp_id=?
14. After committing update transaction
Lors d’exécutions ultérieures, nous obtenons la sortie suivante.
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
Employee object loaded. Id= 101, Name= Final updated name, Salary= 1000.0, {Address= AddressLine1= Test address1, City=Bangalore, Zipcode=12121}
13. Before committing update transaction
14. After committing update transaction
Remarquez qu’il n’y a pas de mises à jour déclenchées après la première exécution car il n’y a pas de mises à jour de valeurs. Remarquez également que le nom de l’employé est « Nom final mis à jour » que nous avons défini après l’invocation de la méthode update(). Cela confirme que Hibernate suivait l’objet pour tout changement et au moment de valider la transaction, cette valeur a été enregistrée.
Hibernate Fusion
Hibernate fusion peut être utilisé pour mettre à jour des valeurs existantes, cependant cette méthode crée une copie de l’objet entité passé et la renvoie. L’objet renvoyé fait partie du contexte persistant et est suivi pour tout changement, l’objet passé n’est pas suivi. C’est la principale différence avec merge() par rapport à toutes les autres méthodes. Regardons cela avec un programme simple.
package com.journaldev.hibernate.main;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.journaldev.hibernate.model.Employee;
import com.journaldev.hibernate.util.HibernateUtil;
public class HibernateMergeExample {
public static void main(String[] args) {
// Travail de préparation
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Employee emp = (Employee) session.load(Employee.class, new Long(101));
System.out.println("Employee object loaded. " + emp);
tx.commit();
// exemple de fusion - données déjà présentes dans les tables
emp.setSalary(25000);
Transaction tx8 = session.beginTransaction();
Employee emp4 = (Employee) session.merge(emp);
System.out.println(emp4 == emp); // returns false
emp.setName("Test");
emp4.setName("Kumar");
System.out.println("15. Before committing merge transaction");
tx8.commit();
System.out.println("16. After committing merge transaction");
// Fermer les ressources
sessionFactory.close();
}
}
La sortie lors de la première exécution est :
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
Employee object loaded. Id= 101, Name= Final updated name, Salary= 1000.0, {Address= AddressLine1= Test address1, City=Bangalore, Zipcode=12121}
false
15. Before committing merge transaction
Hibernate: update EMPLOYEE set emp_name=?, emp_salary=? where emp_id=?
16. After committing merge transaction
Lors d’exécutions ultérieures, la sortie produite est :
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
Employee object loaded. Id= 101, Name= Kumar, Salary= 25000.0, {Address= AddressLine1= Test address1, City=Bangalore, Zipcode=12121}
false
15. Before committing merge transaction
16. After committing merge transaction
Remarquez que l’objet entité retourné par merge() est différent de l’entité passée. Remarquez également qu’au cours de l’exécution ultérieure, le nom est « Kumar », ceci est dû au fait que l’objet retourné est suivi pour tout changement. C’est tout pour les méthodes Session Hibernate save
et update
, j’espère que les exemples ci-dessus vous aideront à clarifier tout doute que vous pourriez avoir.