Hibernate Session merge, update, save, saveOrUpdate, persist example

De Get Docs
Aller à :navigation, rechercher

Hibernate Session est l'interface entre l'application java et le framework d'hibernation. Aujourd'hui, nous allons examiner les méthodes importantes de Session pour enregistrer et mettre à jour les données dans les tables - save, saveOrUpdate, persist, update et fusionner.

Session d'hibernation

[1]

Enregistrer la session d'hibernation

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, c'est pourquoi je n'aime pas cette méthode pour enregistrer des données. Si nous l'utilisons sans transaction et que nous avons une cascade entre les entités, seule l'entité principale est enregistrée à moins que nous ne vidions la session . Pour nos besoins de test, nous avons deux beans entité - 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;

        //Getter setter methods

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

        //Getter setter methods

    @Override
    public String toString() {
        return "AddressLine1= " + addressLine1 + ", City=" + city
                + ", Zipcode=" + zipcode;
    }
}

Voici un programme d'hibernation simple où nous invoquons save() méthode 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) {
        
        // Prep Work
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
        
        //save example - without 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("*****");
        
        //save example - with 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("*****");
        
        //save example - existing row in table
        Session session6 = sessionFactory.openSession();
        Transaction tx6 = session6.beginTransaction();
        Employee emp6 =  (Employee) session6.load(Employee.class, new Long(20));
        
        //update some data
        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("*****");
        
        // Close resources
        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 devons éviter d'enregistrer en dehors des limites de la transaction, sinon les entités mappées ne seront pas enregistrées, ce qui entraînera une incohérence des données. Il est tout à fait normal d'oublier de vider la session car cela ne génère aucune exception ni aucun avertissement.
  • La méthode de sauvegarde Hibernate renvoie immédiatement l'identifiant généré, cela est possible car l'objet principal est enregistré dès que la méthode de sauvegarde est invoquée.
  • S'il existe d'autres objets mappés à partir de l'objet principal, ils sont enregistrés au moment de la validation de la transaction ou lorsque nous vidons la session.
  • Pour les objets qui sont dans un état persistant, enregistrer met à jour les données via la requête de mise à jour. Notez que cela se produit lorsque la transaction est validée. S'il n'y a aucun changement dans l'objet, aucune requête ne sera déclenchée. Si vous exécuterez le programme ci-dessus plusieurs fois, vous remarquerez que les requêtes de mise à jour ne sont pas déclenchées la prochaine fois car il n'y a pas de changement dans les valeurs des colonnes.
  • Hibernate save load entity object to persistent context, si vous mettez à jour les propriétés de l'objet après l'appel de sauvegarde mais avant que la transaction ne soit validée, il sera enregistré dans la base de données.

Hibernation persistante

Hibernate persist est similaire à save (with transaction) et ajoute l'objet entité au contexte persistant, de sorte que toute modification ultérieure est suivie. 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, il sera également enregistré dans la base de données. La deuxième différence est que nous pouvons utiliser persist() méthode 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 de l'identifiant généré. Regardons hibernate persistent 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) {
        
        // Prep Work
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();  
        
        //persist example - with 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("*****");
        
        // Close resources
        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=?
*****

Notez que le premier objet employé est inséré, puis au moment de la validation de la transaction, la requête de mise à jour est exécutée pour mettre à jour la valeur du nom. L'adresse de l'objet mappé est également enregistrée dans la base de données.

Hiberner saveOrUpdate

Hibernate saveOrUpdate génère des requêtes d'insertion ou de mise à jour basées sur les données fournies. Si les données sont présentes dans la base de données, la requête de mise à jour est exécutée. On peut utiliser saveOrUpdate() sans transaction également, mais encore une fois, vous rencontrerez des problèmes avec les objets mappés qui ne sont pas enregistrés si la session n'est pas vidée. Hibernate saveOrUpdate ajoute l'objet entité au contexte persistant et suit toute modification ultérieure. Toute autre modification est enregistrée 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) {
        
        // Prep Work
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
        
        //saveOrUpdate example - without transaction
        Session session5 = sessionFactory.openSession();
        Employee emp5 = HibernateSaveExample.getTestEmployee();
        session5.saveOrUpdate(emp5);
        System.out.println("*****");
        
        //saveOrUpdate example - with 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("*****");

        // Close resources
        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
*****

Notez que sans transaction, seul Employé est enregistré et les informations d'adresse sont perdues. Avec la transaction, l'objet employé est suivi pour toute modification, c'est pourquoi lors du dernier appel, il n'y a pas de mise à jour dans la table Employé même si la valeur a été modifiée entre les deux, la valeur finale reste la même.

Mise à jour de l'hibernation

La mise à jour Hibernate doit être utilisée lorsque nous savons que nous ne mettons à jour que les informations sur l'entité. Cette opération ajoute l'objet entité au contexte persistant et les modifications ultérieures sont suivies et enregistrées 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) {

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

        // update example
        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");

        // Close resources
        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'une exécution ultérieure, 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

Notez qu'aucune mise à jour n'est déclenchée après la première exécution car il n'y a pas de mise à jour dans les valeurs. Notez également que le nom de l'employé est "Nom final mis à jour" que nous avons défini après avoir appelé la méthode update (). Cela confirme qu'hibernate suivait l'objet pour toute modification et au moment de la validation de la transaction, cette valeur a été enregistrée.

Hiberner Fusionner

Hibernate merge peut être utilisé pour mettre à jour les valeurs existantes, mais 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 toute modification, l'objet passé n'est pas suivi. C'est la principale différence entre merge() et 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) {

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

         //merge example - data already present in 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");

        // Close resources
        sessionFactory.close();

    }

}

La sortie en 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

Dans une exécution ultérieure, 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

Notez que l'objet entité renvoyé par merge() est différent de l'entité transmise. Notez également que lors de l'exécution ultérieure, le nom est "Kumar", car l'objet renvoyé est suivi pour toute modification. C'est tout pour Hibernate Session save et update méthodes, j'espère que les exemples ci-dessus vous aideront à clarifier vos doutes.