Hibernate 会话合并、更新、保存、保存或更新、持久化示例

Hibernate Session 是Java应用程序与Hibernate框架之间的接口。今天我们来看看会话中保存和更新表中数据的重要方法--** 保存** 、** saveOrUpdate** 、** 持久化** 、** 更新** 和** 合并** 。

休眠会话

Hibernate会话合并、保持、保存、保存或更新方法examples

休眠会话保存

顾名思义,Hibernate save() 可以用来将实体保存到数据库中。我们可以在事务外部调用此方法,这就是我不喜欢此方法保存数据的原因。如果我们在不使用事务的情况下使用它,并且实体之间有级联,则只保存主实体** ,除非我们刷新会话** 。出于测试目的,我们有两个实体Bean--EmployeeAddress

 1package com.journaldev.hibernate.model;
 2
 3import javax.persistence.Access;
 4import javax.persistence.AccessType;
 5import javax.persistence.Column;
 6import javax.persistence.Entity;
 7import javax.persistence.GeneratedValue;
 8import javax.persistence.GenerationType;
 9import javax.persistence.Id;
10import javax.persistence.OneToOne;
11import javax.persistence.Table;
12
13import org.hibernate.annotations.Cascade;
14
15@Entity
16@Table(name = "EMPLOYEE")
17@Access(value=AccessType.FIELD)
18public class Employee {
19
20    @Id
21    @GeneratedValue(strategy = GenerationType.IDENTITY)
22    @Column(name = "emp_id")
23    private long id;
24
25    @Column(name = "emp_name")
26    private String name;
27
28    @Column(name = "emp_salary")
29    private double salary;
30
31    @OneToOne(mappedBy = "employee")
32    @Cascade(value = org.hibernate.annotations.CascadeType.ALL)
33    private Address address;
34
35        //Getter setter methods
36
37    @Override
38    public String toString() {
39    	return "Id= " + id + ", Name= " + name + ", Salary= " + salary
40    			+ ", {Address= " + address + "}";
41    }
42
43}
 1package com.journaldev.hibernate.model;
 2
 3import javax.persistence.Access;
 4import javax.persistence.AccessType;
 5import javax.persistence.Column;
 6import javax.persistence.Entity;
 7import javax.persistence.GeneratedValue;
 8import javax.persistence.Id;
 9import javax.persistence.OneToOne;
10import javax.persistence.PrimaryKeyJoinColumn;
11import javax.persistence.Table;
12
13import org.hibernate.annotations.GenericGenerator;
14import org.hibernate.annotations.Parameter;
15
16@Entity
17@Table(name = "ADDRESS")
18@Access(value=AccessType.FIELD)
19public class Address {
20
21    @Id
22    @Column(name = "emp_id", unique = true, nullable = false)
23    @GeneratedValue(generator = "gen")
24    @GenericGenerator(name = "gen", strategy = "foreign", parameters = { @Parameter(name = "property", value = "employee") })
25    private long id;
26
27    @Column(name = "address_line1")
28    private String addressLine1;
29
30    @Column(name = "zipcode")
31    private String zipcode;
32
33    @Column(name = "city")
34    private String city;
35
36    @OneToOne
37    @PrimaryKeyJoinColumn
38    private Employee employee;
39
40        //Getter setter methods
41
42    @Override
43    public String toString() {
44    	return "AddressLine1= " + addressLine1 + ", City=" + city
45    			+ ", Zipcode=" + zipcode;
46    }
47}

下面是一个简单的Hibernate程序,其中我们在不同的情况下调用了save()方法。

 1package com.journaldev.hibernate.main;
 2
 3import org.hibernate.Session;
 4import org.hibernate.SessionFactory;
 5import org.hibernate.Transaction;
 6
 7import com.journaldev.hibernate.model.Address;
 8import com.journaldev.hibernate.model.Employee;
 9import com.journaldev.hibernate.util.HibernateUtil;
10
11public class HibernateSaveExample {
12
13    public static void main(String[] args) {
14    	
15    	// Prep Work
16    	SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
17    	
18    	//save example - without transaction
19    	Session session = sessionFactory.openSession();
20    	Employee emp = getTestEmployee();
21    	long id = (Long) session.save(emp);
22    	System.out.println("1. Employee save called without transaction, id="+id);
23    	session.flush(); //address will not get saved without this
24    	System.out.println("*****");
25    	
26    	//save example - with transaction
27    	Transaction tx1 = session.beginTransaction();
28    	Session session1 = sessionFactory.openSession();
29    	Employee emp1 = getTestEmployee();
30    	long id1 = (Long) session1.save(emp1);
31    	System.out.println("2. Employee save called with transaction, id="+id1);
32    	System.out.println("3. Before committing save transaction");
33    	tx1.commit();
34    	System.out.println("4. After committing save transaction");
35    	System.out.println("*****");
36    	
37    	//save example - existing row in table
38    	Session session6 = sessionFactory.openSession();
39    	Transaction tx6 = session6.beginTransaction();
40    	Employee emp6 =  (Employee) session6.load(Employee.class, new Long(20));
41    	
42    	//update some data
43    	System.out.println("Employee Details="+emp6);
44    	emp6.setName("New Name");
45    	emp6.getAddress().setCity("New City");
46    	
47    	long id6 = (Long) session6.save(emp6);
48    	emp6.setName("New Name1"); // will get updated in database
49    	System.out.println("5. Employee save called with transaction, id="+id6);
50    	System.out.println("6. Before committing save transaction");
51    	tx6.commit();
52    	System.out.println("7. After committing save transaction");
53    	System.out.println("*****");
54    	
55    	// Close resources
56    	sessionFactory.close();
57
58    }
59
60    public static Employee getTestEmployee() {
61    	Employee emp = new Employee();
62    	Address add = new Address();
63    	emp.setName("Test Emp");
64    	emp.setSalary(1000);
65    	add.setAddressLine1("Test address1");
66    	add.setCity("Test City");
67    	add.setZipcode("12121");
68    	emp.setAddress(add);
69    	add.setEmployee(emp);
70    	return emp;
71    }
72}

当我们执行上面的程序时,它会产生以下输出。

 1Hibernate: insert into EMPLOYEE (emp_name, emp_salary) values (?, ?)
 21. Employee save called without transaction, id=149
 3Hibernate: insert into ADDRESS (address_line1, city, zipcode, emp_id) values (?, ?, ?, ?)
 4*****
 5Hibernate: insert into EMPLOYEE (emp_name, emp_salary) values (?, ?)
 62. Employee save called with transaction, id=150
 73. Before committing save transaction
 8Hibernate: insert into ADDRESS (address_line1, city, zipcode, emp_id) values (?, ?, ?, ?)
 94. After committing save transaction
10*****
11Hibernate: 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=?
12Employee Details=Id= 20, Name= Kumar1, Salary= 1000.0, {Address= AddressLine1= Test address1, City=Blr, Zipcode=12121}
135. Employee save called with transaction, id=20
146. Before committing save transaction
15Hibernate: update EMPLOYEE set emp_name=?, emp_salary=? where emp_id=?
16Hibernate: update ADDRESS set address_line1=?, city=?, zipcode=? where emp_id=?
177. After committing save transaction
18*****

我们从上面的输出中可以确认的几个要点是:

  • 应避免在事务边界外保存,否则将不保存映射的实体,导致数据不一致。忘记刷新会话是非常正常的,因为它不会抛出任何异常或警告。
  • Hibernate保存方法立即返回生成的id,这是可能的,因为只要调用保存方法,主对象就会被保存。
  • 如果有从主对象映射的其他对象,则在提交事务时或我们刷新会话时保存这些对象。
  • 对于持久化状态的对象,SAVE通过UPDATE查询更新数据。请注意,它在提交事务时发生。如果对象中没有任何更改,则不会触发任何查询。如果您将多次运行上面的程序,您将注意到下一次不会触发更新查询,因为列值没有变化。
  • Hibernate将实体对象保存到持久化上下文中,如果您要在保存调用之后提交事务之前更新对象属性,则会将其保存到数据库中。

休眠持久化

休眠持久化 类似于保存(带事务),它将实体对象添加到** 持久化上下文** ,因此会跟踪进一步的更改。如果在提交事务或刷新会话之前更改了对象属性,则也会将其保存到数据库中。第二个不同之处在于,我们只能在事务的边界内使用Persistent()方法,因此它是安全的,并且可以处理任何级联对象。最后,Persistent不返回任何内容,因此我们需要使用持久化对象来获取生成的标识符值。让我们用一个简单的程序来看一看Hibernate持久化。

 1package com.journaldev.hibernate.main;
 2
 3import org.hibernate.Session;
 4import org.hibernate.SessionFactory;
 5import org.hibernate.Transaction;
 6
 7import com.journaldev.hibernate.model.Employee;
 8import com.journaldev.hibernate.util.HibernateUtil;
 9
10public class HibernatePersistExample {
11
12    public static void main(String[] args) {
13    	
14    	// Prep Work
15    	SessionFactory sessionFactory = HibernateUtil.getSessionFactory();	
16    	
17    	//persist example - with transaction
18    	Session session2 = sessionFactory.openSession();
19    	Transaction tx2 = session2.beginTransaction();
20    	Employee emp2 = HibernateSaveExample.getTestEmployee();
21    	session2.persist(emp2);
22    	System.out.println("Persist called");
23    	emp2.setName("Kumar"); // will be updated in database too
24    	System.out.println("Employee Name updated");
25    	System.out.println("8. Employee persist called with transaction, id="+emp2.getId()+", address id="+emp2.getAddress().getId());
26    	tx2.commit();
27    	System.out.println("*****");
28    	
29    	// Close resources
30    	sessionFactory.close();
31
32    }
33
34}

上述代码产生的输出为:

1Hibernate: insert into EMPLOYEE (emp_name, emp_salary) values (?, ?)
28. Employee persist called with transaction, id=158, address id=158
3Hibernate: insert into ADDRESS (address_line1, city, zipcode, emp_id) values (?, ?, ?, ?)
4Hibernate: update EMPLOYEE set emp_name=?, emp_salary=? where emp_id=?
5*****

注意,插入了第一个Employee对象,然后在事务提交时执行更新查询以更新Name值。映射的对象地址也被保存到数据库中。

Hibernate saveor更新

休眠saveOrUpdate 根据提供的数据生成插入或更新查询。如果数据库中存在数据,则执行更新查询。我们也可以在没有transaction的情况下使用saveOrUpdate(),但是如果会话没有刷新,您将再次面临映射对象无法保存的问题。Hibernate saveOrUpdate将实体对象添加到持久化上下文并跟踪任何进一步的更改。任何进一步的更改都在提交事务时保存,如持久化。

 1package com.journaldev.hibernate.main;
 2
 3import org.hibernate.Session;
 4import org.hibernate.SessionFactory;
 5import org.hibernate.Transaction;
 6
 7import com.journaldev.hibernate.model.Employee;
 8import com.journaldev.hibernate.util.HibernateUtil;
 9
10public class HibernateSaveOrUpdateExample {
11
12    public static void main(String[] args) {
13    	
14    	// Prep Work
15    	SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
16    	
17    	//saveOrUpdate example - without transaction
18    	Session session5 = sessionFactory.openSession();
19    	Employee emp5 = HibernateSaveExample.getTestEmployee();
20    	session5.saveOrUpdate(emp5);
21    	System.out.println("*****");
22    	
23    	//saveOrUpdate example - with transaction
24    	Session session3 = sessionFactory.openSession();
25    	Transaction tx3 = session3.beginTransaction();
26    	Employee emp3 = HibernateSaveExample.getTestEmployee();
27    	session3.saveOrUpdate(emp3);
28    	emp3.setName("Kumar"); //will be saved into DB
29    	System.out.println("9. Before committing saveOrUpdate transaction. Id="+emp3.getId());
30    	tx3.commit();
31    	System.out.println("10. After committing saveOrUpdate transaction");
32    	System.out.println("*****");
33    	
34    	
35    	Transaction tx4 = session3.beginTransaction();
36    	emp3.setName("Updated Test Name"); //Name changed
37    	emp3.getAddress().setCity("Updated City");
38    	session3.saveOrUpdate(emp3);
39    	emp3.setName("Kumar"); //again changed to previous value, so no Employee update
40    	System.out.println("11. Before committing saveOrUpdate transaction. Id="+emp3.getId());
41    	tx4.commit();
42    	System.out.println("12. After committing saveOrUpdate transaction");
43    	System.out.println("*****");
44
45    	// Close resources
46    	sessionFactory.close();
47
48    }
49}

以上程序产生以下输出。

 1Hibernate: insert into EMPLOYEE (emp_name, emp_salary) values (?, ?)
 2*****
 3Hibernate: insert into EMPLOYEE (emp_name, emp_salary) values (?, ?)
 49. Before committing saveOrUpdate transaction. Id=166
 5Hibernate: insert into ADDRESS (address_line1, city, zipcode, emp_id) values (?, ?, ?, ?)
 6Hibernate: update EMPLOYEE set emp_name=?, emp_salary=? where emp_id=?
 710. After committing saveOrUpdate transaction
 8*****
 911. Before committing saveOrUpdate transaction. Id=166
10Hibernate: update ADDRESS set address_line1=?, city=?, zipcode=? where emp_id=?
1112. After committing saveOrUpdate transaction
12*****

请注意,如果没有事务处理,则只会保存员工,并且地址信息会丢失。使用事务Employee对象跟踪任何更改,这就是为什么在最后一次调用中,即使值在两者之间更改,Employee表中也没有更新,最终值保持不变。

Hibernate更新

当我们知道我们只是在更新实体信息时,应该使用Hibernate更新 。此操作将实体对象添加到** 持久化上下文** ,并在提交事务时跟踪并保存进一步的更改。让我们用一个简单的程序来检查这个行为。

 1package com.journaldev.hibernate.main;
 2
 3import org.hibernate.Session;
 4import org.hibernate.SessionFactory;
 5import org.hibernate.Transaction;
 6
 7import com.journaldev.hibernate.model.Employee;
 8import com.journaldev.hibernate.util.HibernateUtil;
 9
10public class HibernateUpdateExample {
11
12    public static void main(String[] args) {
13
14    	// Prep Work
15    	SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
16    	Session session = sessionFactory.openSession();
17    	Transaction tx = session.beginTransaction();
18    	Employee emp = (Employee) session.load(Employee.class, new Long(101));
19    	System.out.println("Employee object loaded. " + emp);
20    	tx.commit();
21
22    	// update example
23    	emp.setName("Updated name");
24    	emp.getAddress().setCity("Bangalore");
25    	Transaction tx7 = session.beginTransaction();
26    	session.update(emp);
27    	emp.setName("Final updated name");
28    	System.out.println("13. Before committing update transaction");
29    	tx7.commit();
30    	System.out.println("14. After committing update transaction");
31
32    	// Close resources
33    	sessionFactory.close();
34
35    }
36
37}

当我们第一次执行上面的程序时,我们得到以下输出。

1Hibernate: 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=?
2Employee object loaded. Id= 101, Name= Test Emp, Salary= 1000.0, {Address= AddressLine1= Test address1, City=Test City, Zipcode=12121}
313. Before committing update transaction
4Hibernate: update EMPLOYEE set emp_name=?, emp_salary=? where emp_id=?
5Hibernate: update ADDRESS set address_line1=?, city=?, zipcode=? where emp_id=?
614. After committing update transaction

在进一步执行时,我们会得到以下输出。

1Hibernate: 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=?
2Employee object loaded. Id= 101, Name= Final updated name, Salary= 1000.0, {Address= AddressLine1= Test address1, City=Bangalore, Zipcode=12121}
313. Before committing update transaction
414. After committing update transaction

请注意,第一次执行后没有激发更新,因为值中没有更新。还要注意,员工姓名是我们在调用UPDATE()方法后设置的最终更新姓名。这证实了Hibernate正在跟踪对象的任何更改,并且在提交事务时保存了此值。

Hibernate合并

Hibernate Merge 可以用来更新已有的值,但是这个方法从传递的Entity对象创建一个副本并返回它。返回的对象是持久上下文的一部分,并被跟踪任何更改,传递的对象不被跟踪。这是Merge()与所有其他方法的主要区别。让我们用一个简单的程序来看看这一点。

 1package com.journaldev.hibernate.main;
 2
 3import org.hibernate.Session;
 4import org.hibernate.SessionFactory;
 5import org.hibernate.Transaction;
 6
 7import com.journaldev.hibernate.model.Employee;
 8import com.journaldev.hibernate.util.HibernateUtil;
 9
10public class HibernateMergeExample {
11
12    public static void main(String[] args) {
13
14    	// Prep Work
15    	SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
16    	Session session = sessionFactory.openSession();
17    	Transaction tx = session.beginTransaction();
18    	Employee emp = (Employee) session.load(Employee.class, new Long(101));
19    	System.out.println("Employee object loaded. " + emp);
20    	tx.commit();
21
22    	 //merge example - data already present in tables
23    	 emp.setSalary(25000);
24    	 Transaction tx8 = session.beginTransaction();
25    	 Employee emp4 = (Employee) session.merge(emp);
26    	 System.out.println(emp4 == emp); // returns false
27    	 emp.setName("Test");
28    	 emp4.setName("Kumar");
29    	 System.out.println("15. Before committing merge transaction");
30    	 tx8.commit();
31    	 System.out.println("16. After committing merge transaction");
32
33    	// Close resources
34    	sessionFactory.close();
35
36    }
37
38}

第一次执行的输出为:

1Hibernate: 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=?
2Employee object loaded. Id= 101, Name= Final updated name, Salary= 1000.0, {Address= AddressLine1= Test address1, City=Bangalore, Zipcode=12121}
3false
415. Before committing merge transaction
5Hibernate: update EMPLOYEE set emp_name=?, emp_salary=? where emp_id=?
616. After committing merge transaction

在进一步的执行中,产生的输出是:

1Hibernate: 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=?
2Employee object loaded. Id= 101, Name= Kumar, Salary= 25000.0, {Address= AddressLine1= Test address1, City=Bangalore, Zipcode=12121}
3false
415. Before committing merge transaction
516. After committing merge transaction

请注意,Merge()返回的实体对象与传递的实体不同。还要注意,在进一步的执行中,名称是kumar,这是因为会跟踪返回的对象是否有任何更改。这就是Hibernate Session save和`update‘方法,希望上面的例子能帮助您澄清任何疑惑。

Published At
Categories with 技术
Tagged with
comments powered by Disqus