Hibernate-sessie is de interface tussen de Java-toepassing en het Hibernate-framework. Vandaag zullen we kijken naar de belangrijke methoden van de sessie voor het opslaan en bijwerken van gegevens in tabellen – save, saveOrUpdate, persist, update en merge.
Hibernate-sessie
Hibernate-sessie opslaan
Zoals de naam van de methode suggereert, kan hibernate save() worden gebruikt om een entiteit op te slaan in de database. We kunnen deze methode buiten een transactie aanroepen, daarom geef ik er de voorkeur aan deze methode niet te gebruiken om gegevens op te slaan. Als we dit zonder transactie gebruiken en we cascaderen tussen entiteiten, dan wordt alleen de primaire entiteit opgeslagen tenzij we de sessie flushen. Voor onze testdoeleinden hebben we twee entiteit-beans – Employee
en 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-methoden
@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-methoden
@Override
public String toString() {
return "AddressLine1= " + addressLine1 + ", City=" + city
+ ", Zipcode=" + zipcode;
}
}
Hier is een eenvoudig Hibernate-programma waarin we de save()
-methode aanroepen in verschillende gevallen.
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) {
// Voorbereidend werk
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
//voorbeeld opslaan - zonder transactie
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("*****");
//voorbeeld opslaan - met transactie
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("*****");
//voorbeeld opslaan - bestaande rij in tabel
Session session6 = sessionFactory.openSession();
Transaction tx6 = session6.beginTransaction();
Employee emp6 = (Employee) session6.load(Employee.class, new Long(20));
//enkele gegevens bijwerken
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("*****");
// Sluit middelen
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;
}
}
Wanneer we het bovenstaande programma uitvoeren, produceert het de volgende uitvoer.
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
*****
Enkele belangrijke punten die we uit de bovenstaande uitvoer kunnen bevestigen zijn:
- We moeten opslaan buiten de transactiegrens vermijden, anders worden gemapte entiteiten niet opgeslagen, wat tot gegevensinconsistentie kan leiden. Het is heel normaal om het flushen van de sessie te vergeten omdat er geen uitzondering of waarschuwing wordt gegenereerd.
- De Hibernate opslaan methode geeft onmiddellijk de gegenereerde id terug, dit is mogelijk omdat het hoofdobject wordt opgeslagen zodra de opslaan methode wordt aangeroepen.
- Als er andere objecten zijn gemapt vanuit het hoofdobject, worden ze opgeslagen op het moment dat de transactie wordt uitgevoerd of wanneer we de sessie flushen.
- Voor objecten die zich in een persistent state bevinden, werkt opslaan de gegevens bij via een update-query. Let op dat dit gebeurt wanneer de transactie wordt uitgevoerd. Als er geen wijzigingen zijn in het object, wordt er geen query uitgevoerd. Als je het bovenstaande programma meerdere keren uitvoert, zul je merken dat er geen updatequery’s worden uitgevoerd omdat er geen wijzigingen zijn in de kolomwaarden.
- Hibernate slaat het laadentiteitsobject op in de persistente context, als je de objecteigenschappen bijwerkt na de oproep tot opslaan maar voordat de transactie is uitgevoerd, worden deze opgeslagen in de database.
Hibernate Persist
Hibernate persist is vergelijkbaar met save (met transactie) en voegt het entiteitsobject toe aan de persistent context, zodat verdere wijzigingen worden bijgehouden. Als de objecteigenschappen worden gewijzigd voordat de transactie is bevestigd of de sessie is geflushed, worden deze ook in de database opgeslagen. Het tweede verschil is dat we de persist()
-methode alleen binnen de grenzen van een transactie kunnen gebruiken, dus het is veilig en zorgt voor eventuele cascaderende objecten. Ten slotte retourneert persist niets, dus moeten we het gepersisteerde object gebruiken om de gegenereerde identificeerderwaarde te krijgen. Laten we naar Hibernate persist kijken met een eenvoudig 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 HibernatePersistExample {
public static void main(String[] args) {
// Voorbereiding
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
// Voorbeeld van persist - met transactie
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("*****");
// Sluit resources
sessionFactory.close();
}
}
Uitvoer geproduceerd door bovenstaande code is:
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=?
*****
Merk op dat het eerste werknemersobject wordt ingevoegd, vervolgens bij het bevestigen van de transactie wordt een updatequery uitgevoerd om de naamwaarde bij te werken. Ook wordt het gemapte objectadres opgeslagen in de database.
Hibernate saveOrUpdate
Hibernate saveOrUpdate resulteert in invoeg- of updatequery’s op basis van de verstrekte gegevens. Als de gegevens aanwezig zijn in de database, wordt een updatequery uitgevoerd. We kunnen saveOrUpdate()
ook zonder transactie gebruiken, maar opnieuw zul je problemen tegenkomen met gemapte objecten die niet worden opgeslagen als de sessie niet wordt geflusht. Hibernate saveOrUpdate voegt het entiteitobject toe aan de blijvende context en volgt verdere wijzigingen. Eventuele verdere wijzigingen worden opgeslagen op het moment dat de transactie wordt uitgevoerd, zoals bij 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) {
// Voorbereidend werk
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
// Voorbeeld van saveOrUpdate - zonder transactie
Session session5 = sessionFactory.openSession();
Employee emp5 = HibernateSaveExample.getTestEmployee();
session5.saveOrUpdate(emp5);
System.out.println("*****");
// Voorbeeld van saveOrUpdate - met transactie
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("*****");
// Sluit resources
sessionFactory.close();
}
}
Het bovenstaande programma produceert de volgende uitvoer.
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
*****
Let op dat zonder transactie alleen Employee wordt opgeslagen en de adresinformatie verloren gaat. Met transactie wordt het werknemerobject gevolgd voor eventuele wijzigingen, daarom is er in de laatste oproep geen update in de Employee-tabel, ook al is de waarde tussendoor gewijzigd, de uiteindelijke waarde blijft hetzelfde.
Hibernate update
Hibernate update moet worden gebruikt wanneer we weten dat we alleen de entiteitsinformatie bijwerken. Deze bewerking voegt het entiteitobject toe aan de blijvende context en verdere wijzigingen worden gevolgd en opgeslagen wanneer de transactie wordt uitgevoerd. Laten we dit gedrag controleren met een eenvoudig 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) {
// Voorbereidend werk
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();
// voorbeeld bijwerken
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");
// Sluit bronnen
sessionFactory.close();
}
}
Wanneer we het bovenstaande programma voor de eerste keer uitvoeren, krijgen we de volgende uitvoer.
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
Bij verdere uitvoering krijgen we de volgende uitvoer.
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
Merk op dat er na de eerste uitvoering geen updates worden uitgevoerd omdat er geen wijzigingen zijn in de waarden. Let ook op dat de naam van de werknemer “Laatst bijgewerkte naam” is die we hebben ingesteld na het aanroepen van de update() methode. Dit bevestigt dat Hibernate het object bijhield voor eventuele wijzigingen en dat deze waarde bij het committen van de transactie werd opgeslagen.
Hibernate samenvoegen
Hibernate samenvoegen kan worden gebruikt om bestaande waarden bij te werken, echter deze methode maakt een kopie van het doorgegeven entiteit object en retourneert het. Het geretourneerde object maakt deel uit van de persistente context en wordt bijgehouden voor eventuele wijzigingen, het doorgegeven object wordt niet bijgehouden. Dit is het belangrijkste verschil met merge() ten opzichte van alle andere methoden. Laten we dit bekijken met een eenvoudig 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) {
// Voorbereidend werk
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();
// samenvoegingsvoorbeeld - gegevens al aanwezig in tabellen
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");
// Sluit bronnen
sessionFactory.close();
}
}
Uitvoer bij eerste uitvoering is:
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
Bij verdere uitvoering wordt de volgende uitvoer geproduceerd:
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
Merk op dat het entiteitsobject dat door merge() wordt geretourneerd, verschilt van de meegegeven entiteit. Let ook op dat in verdere uitvoering de naam “Kumar” is, dit komt doordat het geretourneerde object wordt gevolgd voor eventuele wijzigingen. Dat is alles voor Hibernate Session save
en update
methoden, ik hoop dat de bovenstaande voorbeelden je zullen helpen bij het verduidelijken van eventuele twijfels die je hebt.