Hibernate Session merge,update,save,saveOrUpdate,persist
Hibernate Session是java应用程序和hibernate框架之间的接口。今天我们将研究Session在表中保存和更新数据的重要方法 - save,saveOrUpdate,persist,update和merge。
目录[ 隐藏 ]
Hibernate Session
Hibernate Session Save
正如方法名称所示,hibernate save()可用于将实体保存到数据库。我们可以在事务外部调用此方法,这就是为什么我不喜欢这种方法来保存数据。如果我们在没有事务的情况下使用它,并且我们在实体之间进行级联,那么除非我们刷新会话,否则只保存主实体。
为了我们的测试目的,我们有两个实体bean - Employee
和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;
}
}
这是一个简单的hibernate程序,我们save()
在不同的情况下调用方法。
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;
}
}
当我们执行上面的程序时,它产生以下输出。
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
*****
我们可以从上面的输出中确认的几个要点是:
- 我们应该避免保存外部事务边界,否则将不会保存映射实体导致数据不一致。忘记刷新会话是很正常的,因为它不会抛出任何异常或警告。
- Hibernate save方法立即返回生成的id,这是可能的,因为一旦调用了save方法,就会保存主对象。
- 如果从主对象映射了其他对象,则会在提交事务或刷新会话时保存它们。
- 对于处于持久状态的对象,save通过更新查询更新数据。请注意,它在事务提交时发生。如果对象没有更改,则不会触发任何查询。如果您将多次运行上面的程序,您会注意到下次不会触发更新查询,因为列值没有变化。
- Hibernate将加载实体对象保存到持久化上下文,如果在保存调用之后但在提交事务之前更新对象属性,则将其保存到数据库中。
Hibernate Persist
Hibernate persist类似于save(with transaction),它将实体对象添加到持久化上下文中,因此跟踪任何进一步的更改。如果在提交事务或刷新会话之前更改了对象属性,则它也将保存到数据库中。
第二个区别是我们persist()
只能在事务的边界内使用方法,因此它是安全的并且可以处理任何级联对象。
最后,persist不返回任何内容,因此我们需要使用持久化对象来获取生成的标识符值。让我们看看hibernate坚持使用一个简单的程序。
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();
}
}
上述代码产生的输出是:
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=?
*****
请注意,插入了第一个雇员对象,然后在事务提交时,执行更新查询以更新名称值。映射的对象地址也保存到数据库中。
Hibernate saveOrUpdate
Hibernate saveOrUpdate根据提供的数据生成插入或更新查询。如果数据存在于数据库中,则执行更新查询。
我们也可以在saveOrUpdate()
没有事务的情况下使用,但是如果没有刷新会话,你将再次遇到未被保存的映射对象的问题。
Hibernate saveOrUpdate将实体对象添加到持久上下文并跟踪任何进一步的更改。在提交事务时保存任何进一步的更改,如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();
}
}
以上程序产生以下输出。
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
*****
请注意,没有事务,只会保存Employee并丢失地址信息。
随着事务员工对象被跟踪任何更改,这就是为什么在最后一次调用中,即使在两者之间更改了值,Employee表中也没有更新,最终值保持不变。
Hibernate update
当我们知道我们只更新实体信息时,应该使用Hibernate更新。此操作将实体对象添加到持久上下文,并在提交事务时跟踪和保存进一步的更改。让我们用一个简单的程序检查这个行为。
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();
}
}
当我们第一次执行上面的程序时,我们得到以下输出。
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
在进一步执行时,我们得到以下输出。
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
请注意,首次执行后没有触发更新,因为值中没有更新。另请注意,员工姓名是我们在调用update()方法后设置的“最终更新名称”。这确认了hibernate正在跟踪对象的任何更改,并且在提交事务时,此值已保存。
Hibernate Merge
Hibernate merge可用于更新现有值,但此方法从传递的实体对象创建副本并返回它。返回的对象是持久化上下文的一部分,并跟踪任何更改,不跟踪传递的对象。这是与所有其他方法的merge()的主要区别。让我们用一个简单的程序来看看这个。
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();
}
}
第一次执行的输出是:
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
在进一步执行中,产生的输出是:
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
请注意,merge()返回的实体对象与传递的实体不同。另请注意,在进一步执行中,name是“Kumar”,这是因为跟踪返回的对象是否有任何更改。
这就是Hibernate会话 save
和update
方法的全部内容,我希望上面的例子可以帮助您澄清任何疑问。
转载来源:https://www.journaldev.com/3481/hibernate-session-merge-vs-update-save-saveorupdate-persist-example