Esempio di merge, update, save, saveOrUpdate, persist della sessione di Hibernate

Il Sessione di Hibernate è l’interfaccia tra l’applicazione Java e il framework Hibernate. Oggi esamineremo i metodi importanti della Sessione per salvare e aggiornare i dati nelle tabelle – save, saveOrUpdate, persist, update e merge.

Sessione di Hibernate

Salvataggio della Sessione di Hibernate

Come suggerisce il nome del metodo, hibernate save() può essere utilizzato per salvare l’entità nel database. Possiamo invocare questo metodo al di fuori di una transazione, ecco perché non mi piace questo metodo per salvare i dati. Se lo usiamo senza transazione e abbiamo cascata tra le entità, allora viene salvata solo l’entità primaria a meno che non si flushi la sessione. Per i nostri scopi di test abbiamo due entità – Employee e 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;

        //Metodi getter 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;

        //Metodi getter setter

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

Ecco un semplice programma di hibernate in cui stiamo invocando il metodo save() in diversi casi.

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) {
		
		// Lavoro preparatorio
		SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
		
		//esempio di salvataggio - senza transazione
		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("*****");
		
		//esempio di salvataggio - con transazione
		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("*****");
		
		//esempio di salvataggio - riga esistente nella tabella
		Session session6 = sessionFactory.openSession();
		Transaction tx6 = session6.beginTransaction();
		Employee emp6 =  (Employee) session6.load(Employee.class, new Long(20));
		
		//aggiornare alcuni dati
		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("*****");
		
		// Chiudere le risorse
		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;
	}
}

Quando eseguiamo il programma sopra, produce il seguente output.

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
*****

Alcuni punti importanti che possiamo confermare dall’output sono:

  • Dovremmo evitare di salvare al di fuori del confine della transazione, altrimenti le entità mappate non verranno salvate causando inconsistenza dei dati. È molto normale dimenticare di eseguire il flushing della sessione perché non genera alcuna eccezione o avviso.
  • Il metodo di salvataggio di Hibernate restituisce immediatamente l’id generato, questo è possibile perché l’oggetto principale viene salvato non appena il metodo di salvataggio viene invocato.
  • Se ci sono altri oggetti mappati dall’oggetto principale, vengono salvati al momento del commit della transazione o quando eseguiamo il flushing della sessione.
  • Per gli oggetti che sono in stato persistente, il salvataggio aggiorna i dati attraverso la query di aggiornamento. Notare che ciò avviene quando la transazione viene eseguita. Se non ci sono modifiche nell’oggetto, non verrà eseguita alcuna query. Se eseguirai il programma sopra più volte, noterai che le query di aggiornamento non vengono eseguite la volta successiva perché non ci sono cambiamenti nei valori delle colonne.
  • Il salvataggio di Hibernate carica l’oggetto entità nel contesto persistente, se aggiornerai le proprietà dell’oggetto dopo la chiamata di salvataggio ma prima che la transazione venga eseguita, verrà salvato nel database.

Salvataggio Persistente di Hibernate

Il salvataggio persistente di Hibernate è simile al salvataggio (con transazione) e aggiunge l’oggetto entità al contesto persistente, quindi ogni ulteriore modifica viene tracciata. Se le proprietà dell’oggetto vengono cambiate prima che la transazione venga confermata o che la sessione venga svuotata, verranno comunque salvate nel database. La seconda differenza è che possiamo utilizzare il metodo persist() solo all’interno del limite di una transazione, quindi è sicuro e si occupa di eventuali oggetti in cascata. Infine, persist non restituisce nulla, quindi dobbiamo utilizzare l’oggetto persistito per ottenere il valore dell’identificatore generato. Diamo uno sguardo al salvataggio persistente di Hibernate con un programma semplice.

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) {
		
		// Lavoro preliminare
		SessionFactory sessionFactory = HibernateUtil.getSessionFactory();	
		
		// Esempio di persistenza - con transazione
		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("*****");
		
		// Chiudere le risorse
		sessionFactory.close();

	}

}

L’output prodotto dal codice sopra è:

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=?
*****

Nota che il primo oggetto dipendente viene inserito, quindi al momento della conferma della transazione, viene eseguita la query di aggiornamento per aggiornare il valore del nome. Anche l’indirizzo dell’oggetto mappato viene salvato nel database.

Salva o Aggiorna di Hibernate

Hibernate saveOrUpdate si traduce in query di inserimento o aggiornamento in base ai dati forniti. Se i dati sono presenti nel database, viene eseguita la query di aggiornamento. Possiamo utilizzare saveOrUpdate() anche senza transazione, ma di nuovo ci troveremo di fronte ai problemi con gli oggetti mappati che non vengono salvati se la sessione non viene svuotata. Hibernate saveOrUpdate aggiunge l’oggetto entità al contesto persistente e tiene traccia di eventuali ulteriori modifiche. Eventuali ulteriori modifiche vengono salvate al momento del commit della transazione, come con il metodo 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) {
		
		// Lavoro preliminare
		SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
		
		// Esempio di saveOrUpdate - senza transazione
		Session session5 = sessionFactory.openSession();
		Employee emp5 = HibernateSaveExample.getTestEmployee();
		session5.saveOrUpdate(emp5);
		System.out.println("*****");
		
		// Esempio di saveOrUpdate - con transazione
		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("*****");

		// Chiudi risorse
		sessionFactory.close();

	}
}

Il programma sopra produce il seguente output.

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
*****

Nota che senza transazione, viene salvato solo Employee e le informazioni sull’indirizzo vengono perse. Con la transazione, l’oggetto employee viene tracciato per eventuali modifiche, ecco perché nell’ultima chiamata non c’è un aggiornamento nella tabella Employee anche se il valore è stato modificato nel frattempo, il valore finale rimane lo stesso.

Hibernate update

Hibernate update dovrebbe essere utilizzato quando sappiamo che stiamo solo aggiornando le informazioni sull’entità. Questa operazione aggiunge l’oggetto entità al contesto persistente e le modifiche ulteriori vengono tracciate e salvate quando viene eseguito il commit della transazione. Verifichiamo questo comportamento con un semplice programma.

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) {

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

		// esempio di aggiornamento
		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");

		// Chiudere le risorse
		sessionFactory.close();

	}

}

Quando eseguiamo il programma sopra per la prima volta, otteniamo il seguente output.

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

All’esecuzione successiva, otteniamo il seguente output.

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

Nota che non ci sono aggiornamenti attivati dopo la prima esecuzione perché non ci sono aggiornamenti nei valori. Nota anche che il nome dell’impiegato è “Nome finale aggiornato” che abbiamo impostato dopo aver invocato il metodo update(). Questo conferma che Hibernate stava tracciando l’oggetto per eventuali modifiche e al momento di eseguire il commit della transazione, questo valore è stato salvato.

Unione di Hibernate

L’unione di Hibernate può essere utilizzata per aggiornare i valori esistenti, tuttavia questo metodo crea una copia dall’oggetto entità passato e la restituisce. L’oggetto restituito fa parte del contesto persistente e viene tracciato per eventuali modifiche, l’oggetto passato non viene tracciato. Questa è la differenza principale con merge() rispetto a tutti gli altri metodi. Vediamo questo con un semplice programma.

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) {

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

		 // esempio di unione - dati già presenti nelle tabelle
		 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");

		// Chiudere le risorse
		sessionFactory.close();

	}

}

L’output nella prima esecuzione è:

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

Nell’esecuzione successiva, viene prodotto l’output:

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

Si noti che l’oggetto entità restituito da merge() è diverso dall’entità passata. Si noti anche che nell’esecuzione successiva, il nome è “Kumar”, questo perché l’oggetto restituito viene tracciato per eventuali modifiche. Questo è tutto per il Sessione di Hibernate metodi save e update, spero che gli esempi sopra ti aiutino a chiarire eventuali dubbi che hai.

Source:
https://www.digitalocean.com/community/tutorials/hibernate-session-merge-vs-update-save-saveorupdate-persist-example