hibernate save()方法可以保存实体到数据库,正如方法名称save这个单词所代表的意思。咱们可以在事务以外调用这个方法,这也是我不喜欢使用这个方法保存数据的缘由。假如两个实体之间有关系(例如employee表和address表有一对一关系),若是在没有事务的状况下调用这个方法保存employee这个实体,除非调用flush()这个方法,不然仅仅employee实体会被保存。java
为了方便理解,简化Employee.java的属性。git
/* * @(#)Employee.java Created on 2016年4月10日 * Copyright (c) 2016. All rights reserved. */ package nd.esp.com.hibernate.model; 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") public class Employee { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "emp_id") private long id; @Column(name = "emp_name") private String name; @OneToOne(mappedBy = "employee") @Cascade(value = org.hibernate.annotations.CascadeType.ALL) private Address address; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } @Override public String toString() { return "Employee [id=" + id + ", name=" + name + "]"; } }
为了方便理解,简化Address.java的属性。github
/* * @(#)Address.java Created on 2016年4月10日 * Copyright (c) 2016. All rights reserved. */ package nd.esp.com.hibernate.model; 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") 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 = "city") private String city; @OneToOne @PrimaryKeyJoinColumn private Employee employee; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public Employee getEmployee() { return employee; } public void setEmployee(Employee employee) { this.employee = employee; } @Override public String toString() { return "Address [id=" + id + ", city=" + city + "]"; } }
如下是简单的hibernate程序,演示save()方法的使用。sql
/* * @(#)HibernateSaveExample.java Created on 2016年4月10日 * Copyright (c) 2016. All rights reserved. */ package nd.esp.com.hibernate.example; import nd.esp.com.hibernate.model.Address; import nd.esp.com.hibernate.model.Employee; import nd.esp.com.hibernate.utils.HibernateUtil; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; public class HibernateSaveExample { public static void main(String[] args) { SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); System.out.println("***********************************************"); // 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(3)); // 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"); add.setCity("Test City"); emp.setAddress(add); add.setEmployee(emp); return emp; } }
执行上述示例程序,输出结果(第一次)。数据库
*********************************************** Hibernate: insert into EMPLOYEE (emp_name) values (?) 1. Employee save called without transaction, id=15 Hibernate: insert into ADDRESS (city, emp_id) values (?, ?) *********************************************** Hibernate: insert into EMPLOYEE (emp_name) values (?) 2. Employee save called with transaction, id=16 3. Before committing save transaction 4. After committing save transaction *********************************************** Hibernate: select employee0_.emp_id as emp1_1_1_, employee0_.emp_name as emp2_1_1_, address1_.emp_id as emp1_0_0_, address1_.city as city2_0_0_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=? Employee Details=Employee [id=3, name=Test Emp] 5. Employee save called with transaction, id=3 6. Before committing save transaction Hibernate: update ADDRESS set city=? where emp_id=? Hibernate: update EMPLOYEE set emp_name=? where emp_id=? 7. After committing save transaction ***********************************************
执行上述示例程序,输出结果(第二次)。安全
*********************************************** Hibernate: insert into EMPLOYEE (emp_name) values (?) 1. Employee save called without transaction, id=17 Hibernate: insert into ADDRESS (city, emp_id) values (?, ?) *********************************************** Hibernate: insert into EMPLOYEE (emp_name) values (?) 2. Employee save called with transaction, id=18 3. Before committing save transaction 4. After committing save transaction *********************************************** Hibernate: select employee0_.emp_id as emp1_1_1_, employee0_.emp_name as emp2_1_1_, address1_.emp_id as emp1_0_0_, address1_.city as city2_0_0_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=? Employee Details=Employee [id=3, name=New Name1] 5. Employee save called with transaction, id=3 6. Before committing save transaction 7. After committing save transaction ***********************************************
从上述的输出能够获得如下重要的几点:session
HibernateSaveExample.java
,会发现从第二次开始程序就不会发送update语句。由于hibernate在更新以前会先select,查询该持久化对象,发现该对象和数据库中的一致,就不会作update操做。hibernate persist()方法与save()方法(在事务中执行)相似,persist()方法会将实体对象添加到持久化上下文中,如此被保存的实体后续改变会被记录。若是在提交事务或者会话flush(),对象的属性被从新赋值,那么这个变化也会被保存到数据库中。app
第二个不一样在于persist()方法只可以在事务内执行,因此它可以很好地保证关联对象的安全与存储(原文:Second difference is that we can use persist() method only within the boundary of a transaction, so it’s safe and takes care of any cascaded objects.)。(发现原做者的第一点让人很疑惑,感受是persist()不在事务中执行就会报错。通过测试,persist()在事务外运行不会报错,可是不会插入数据到数据库。原做者的意思多是:persist()方法只可以在事务中被执行,才可以将数据插入到数据库中)ide
最后,persist()方法返回值是void,也就是说不会返回任何的值。测试
如下是简单的hibernate程序,演示persist()方法的使用。
/* * @(#)HibernatePersistExample.java Created on 2016年4月10日 * Copyright (c) 2016. All rights reserved. */ package nd.esp.com.hibernate.example; import nd.esp.com.hibernate.model.Address; import nd.esp.com.hibernate.model.Employee; import nd.esp.com.hibernate.utils.HibernateUtil; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; public class HibernatePersistExample { public static void main(String[] args) { // Prep Work SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); System.out.println("***********************************************"); // persist example - with transaction Session session2 = sessionFactory.openSession(); Transaction tx2 = session2.beginTransaction(); Employee emp2 = 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(); } public static Employee getTestEmployee() { Employee emp = new Employee(); Address add = new Address(); emp.setName("Test Emp"); add.setCity("Test City"); emp.setAddress(add); add.setEmployee(emp); return emp; } }
执行上述示例程序,输出结果。
*********************************************** Hibernate: insert into EMPLOYEE (emp_name) values (?) Persist called Employee Name updated 8. Employee persist called with transaction, id=19, address id=19 Hibernate: insert into ADDRESS (city, emp_id) values (?, ?) Hibernate: update EMPLOYEE set emp_name=? where emp_id=? ***********************************************
须要注意,第一次employee对象被插入数据库,提交事务的时候执行address实体的插入操做,因为employee实体name属性从新赋值,因此执行update操做。
hibernate saveOrUpdate()方法会执行插入或者更新操做。若是该对象在数据库中已经存在则更新,不存在则插入。
saveOrUpdate()方法能够在没有事务的状况下执行,可是若是没有手动调用flush()方法会面临关联对象不被保存的问题
save()方法与saveOrUpdate()方法最大的不一样点在于,saveOrUpdate()方法会将实体对象添加到持久化上下文中,该实体的后续改变会被跟踪。
如下是简单的hibernate程序,演示saveOrUpdate()方法的使用。
/* * @(#)HibernateSaveOrUpdateExample.java Created on 2016年4月10日 * Copyright (c) 2016. All rights reserved. */ package nd.esp.com.hibernate.example; import nd.esp.com.hibernate.model.Address; import nd.esp.com.hibernate.model.Employee; import nd.esp.com.hibernate.utils.HibernateUtil; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; public class HibernateSaveOrUpdateExample { public static void main(String[] args) { // Prep Work SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); System.out.println("***********************************************"); // saveOrUpdate example - without transaction Session session5 = sessionFactory.openSession(); Employee emp5 = getTestEmployee(); session5.saveOrUpdate(emp5); System.out.println("***********************************************"); // saveOrUpdate example - with transaction Session session3 = sessionFactory.openSession(); Transaction tx3 = session3.beginTransaction(); Employee emp3 = 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(); } public static Employee getTestEmployee() { Employee emp = new Employee(); Address add = new Address(); emp.setName("Test Emp"); add.setCity("Test City"); emp.setAddress(add); add.setEmployee(emp); return emp; } }
执行上述示例程序,输出结果。
*********************************************** Hibernate: insert into EMPLOYEE (emp_name) values (?) *********************************************** Hibernate: insert into EMPLOYEE (emp_name) values (?) 9. Before committing saveOrUpdate transaction. Id=21 Hibernate: insert into ADDRESS (city, emp_id) values (?, ?) Hibernate: update EMPLOYEE set emp_name=? where emp_id=? 10. After committing saveOrUpdate transaction *********************************************** 11. Before committing saveOrUpdate transaction. Id=21 Hibernate: update ADDRESS set city=? where emp_id=? 12. After committing saveOrUpdate transaction ***********************************************
注意若是没有事务,仅仅是employee实体被保存到数据库,而address的信息丢失了。
在事务tx4中的几行代码employee实体的name属性先被修改成“Updated Test Name”,以后又被赋值为原来的值“Kumar”,所以employee这个实体在事务提交以前并无改变,因此并无update操做。
当肯定只更新实体信息时使用Hibernate update()方法。update()方法会将实体添加到持久化上下文,实体后续的改变会被跟踪而且当事务提交时这些改变会被保存到数据库中。
如下是简单的hibernate程序,update()方法的使用。
/* * @(#)HibernateUpdateExample.java Created on 2016年4月10日 * Copyright (c) 2016. All rights reserved. */ package nd.esp.com.hibernate.example; import nd.esp.com.hibernate.model.Employee; import nd.esp.com.hibernate.utils.HibernateUtil; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; public class HibernateUpdateExample { public static void main(String[] args) { // Prep Work SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); System.out.println("***********************************************"); Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Employee emp = (Employee) session.load(Employee.class, new Long(19)); System.out.println("Employee object loaded. " + emp); tx.commit(); System.out.println("***********************************************"); // 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"); System.out.println("***********************************************"); // Close resources sessionFactory.close(); } }
执行上述示例程序,输出结果(第一次)。
*********************************************** Hibernate: select employee0_.emp_id as emp1_1_1_, employee0_.emp_name as emp2_1_1_, address1_.emp_id as emp1_0_0_, address1_.city as city2_0_0_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=? Employee object loaded. Employee [id=19, name=Kumar] *********************************************** 13. Before committing update transaction Hibernate: update ADDRESS set city=? where emp_id=? Hibernate: update EMPLOYEE set emp_name=? where emp_id=? 14. After committing update transaction ***********************************************
执行上述示例程序,输出结果(第二次)。
*********************************************** Hibernate: select employee0_.emp_id as emp1_1_1_, employee0_.emp_name as emp2_1_1_, address1_.emp_id as emp1_0_0_, address1_.city as city2_0_0_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=? Employee object loaded. Employee [id=19, name=Final updated name] *********************************************** 13. Before committing update transaction 14. After committing update transaction ***********************************************
注意第二次运行并无执行update操做,由于employee实体与数据库中的一致。还有语句:
session.update(emp); emp.setName("Final updated name");
修改employee实体name属性值为:“Final updated name”,是在update()方法以后,而最后保存到数据库中是“Final updated name”,代表hibernate update()方法会跟踪实体的改变,在提交事务时保存到数据库中。
hibernate merge()方法被用于更新数据库中的记录,然而merge()方法经过建立一个传递进来的实体对象副本而且将这个副本做为返回值返回。返回值属于持久化上下文,可以跟踪实体的改变,而传递进来的实体并不能被跟踪。这一点是merge()方法与其余方法最大的不一样。
如下是简单的hibernate程序,merge()方法的使用。
/* * @(#)HibernateMergeExample.java Created on 2016年4月10日 * Copyright (c) 2016. All rights reserved. */ package nd.esp.com.hibernate.example; import nd.esp.com.hibernate.model.Employee; import nd.esp.com.hibernate.utils.HibernateUtil; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; public class HibernateMergeExample { public static void main(String[] args) { // Prep Work SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); System.out.println("***********************************************"); Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Employee emp = (Employee) session.load(Employee.class, new Long(19)); System.out.println("Employee object loaded. " + emp); tx.commit(); System.out.println("***********************************************"); // merge example - data already present in tables emp.setName("test1"); Transaction tx8 = session.beginTransaction(); Employee emp4 = (Employee) session.merge(emp); System.out.println(emp4 == emp); // returns false emp.setName("test2"); emp4.setName("merge"); System.out.println("15. Before committing merge transaction"); tx8.commit(); System.out.println("16. After committing merge transaction"); System.out.println("***********************************************"); // Close resources sessionFactory.close(); } }
执行上述示例程序,输出结果(第一次)。
*********************************************** Hibernate: select employee0_.emp_id as emp1_1_1_, employee0_.emp_name as emp2_1_1_, address1_.emp_id as emp1_0_0_, address1_.city as city2_0_0_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=? Employee object loaded. Employee [id=19, name=Kumar] *********************************************** false 15. Before committing merge transaction Hibernate: update EMPLOYEE set emp_name=? where emp_id=? 16. After committing merge transaction ***********************************************
执行上述示例程序,输出结果(第二次)。
*********************************************** Hibernate: select employee0_.emp_id as emp1_1_1_, employee0_.emp_name as emp2_1_1_, address1_.emp_id as emp1_0_0_, address1_.city as city2_0_0_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=? Employee object loaded. Employee [id=19, name=merge] *********************************************** false 15. Before committing merge transaction 16. After committing merge transaction ***********************************************
注意merge()方法传递进入的实体与返回值实体是不同的,
Employee emp4 = (Employee) session.merge(emp); emp.setName("test2"); emp4.setName("merge");
上述代码会将employee表的name属性赋值为“merge”,由于返回实体emp4属于持久化上下文,会被跟踪改变。
以上内容翻译自http://www.journaldev.com/3481/hibernate-save-vs-saveorupdate-vs-persist-vs-merge-vs-update-explanation-with-examples。例子代码作了一点简化,而且工程化,能够在以下地址找到上述例子工程:https://github.com/xiaoheike/HibernateSavePersistUpdateMergeDiff
save()方法:
persist()方法:
saveOrUpdate()方法:
update()方法:
merge()方法:
教程结束,感谢阅读。
欢迎转载,但请注明本文连接,谢谢。
2016/4/10 星期日 17:05:41
2016/4/15 星期五 18:12:41 修改关于persist()方法与事务关系描述