Hibernate Session 是Java应用程序与Hibernate框架之间的接口。今天我们来看看会话中保存和更新表中数据的重要方法--** 保存** 、** saveOrUpdate** 、** 持久化** 、** 更新** 和** 合并** 。
休眠会话
休眠会话保存
顾名思义,Hibernate save() 可以用来将实体保存到数据库中。我们可以在事务外部调用此方法,这就是我不喜欢此方法保存数据的原因。如果我们在不使用事务的情况下使用它,并且实体之间有级联,则只保存主实体** ,除非我们刷新会话** 。出于测试目的,我们有两个实体Bean--Employee
和Address
。
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‘方法,希望上面的例子能帮助您澄清任何疑惑。