标签:
二、SaveOrUpdate()
saveOrUpdate()方法会执行插入或者更新操作。如果该对象在数据库中已经存在则更新,不存在则插入。
也可以在没有事务的情况下执行,但是如果没有手动调用flush()方法会面临关联对象不被保存的问题
save()方法与saveOrUpdate()方法最大的不同点在于:saveOrUpdate()方法会将实体对象添加到持久化上下文中,该实体的后续改变会被跟踪。
例子:
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操作。
如果某对象处于游离态,游离态是指该对象的id值为空。hibernate判断一个对象在数据库中是否存在不是看对象的其他信息,而是判断该id在数据库中是不是存在。如果id为空,那自然是不存在,所以当我们调用merge方法的时候,就会直接执行插入操作。这一点有点像saveorupdate()方法。
Object merge(Object object) throws HibernateException
object
- a detached instance with state to be copiedHibernateException
首先从参数说明来看,merge的参数应该是一个处于托管状态的实例对象,而返回值则是一个持久化对象。但是这里的参数并不是一定要是托管状态的对象,它还可以是瞬态和持久化的实例对象。正因如此,才使merge方法变得复杂化。
经代码检验从merge方法产生的效果来看,它和saveOrUpdate方法相似,因此虽然上面提到是因为参数状态的不同造成复杂化,但是这里我并不打算分参数的不同状态来理解merge,而是根据参数有无id或id是否已经存在来理解merge。个人认为这样更容易理解,而且从执行他们两个方法而产生的sql语句来看是一样的。
1. 参数实例对象没有提供id或提供的id在数据库中不存在:这时merge将执行插入操作,产生的sql语句如下,
Hibernate: select max(uid) from user
Hibernate: insert into hibernate1.user (name, age, uid) values (?, ?, ?)
2. 参数实例对象的id在数据库中已经存在,此时又有两种情况:
(1)如果对象有改动,则执行更新操作,产生sql语句有,
Hibernate: select user0_.uid as uid0_0_, user0_.name as name0_0_, user0_.age as age0_0_ from hibernate1.user user0_ where user0_.uid=?
Hibernate: update hibernate1.user set name=?, age=? where uid=?
(2)如果对象为改动,则执行查询操作,产生的语句有,
Hibernate: select user0_.uid as uid0_0_, user0_.name as name0_0_, user0_.age as age0_0_ from hibernate1.user user0_ where user0_.uid=?
不管哪种情况,merge的返回值都是一个持久化的实例对象,但对于参数而言不会改变它的状态。
虽然从功能上merge方法与saveOrUpdate类似,但他们仍有区别。现在有这样一种情况:我们先通过session的get方法得到一个对象u,然后关掉session,再打开一个session并执行saveOrUpdate(u)。此时我们可以看到抛出异常:Exception in thread "main" org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session,即在session缓存中不允许有两个id相同的对象。不过若使用merge方法则不会异常,其实从merge的中文意思(合并)我们就可以理解了。
save()、saveOrUpdate()、merge()的区别
标签:
原文地址:http://www.cnblogs.com/hr1997/p/5827057.html