hibernate中update和merge的区别

        在说这两者的区别时,有必要把hibernate对象三种状态说一下:

        翻译自Hibernate的参考文档

        Hibernate定义并支持下列对象状态(state):
        瞬时(Transient) - 由new操作符创建,且尚未与Hibernate Session 关联的对象被认定为瞬时(Transient)的。瞬时(Transient)对象不会被持久化到数据库中,也不会被赋予持久化标识(identifier)。 如果瞬时(Transient)对象在程序中没有被引用,它会被垃圾回收器(garbage collector)销毁。 使用Hibernate Session可以将其变为持久(Persistent)状态。(Hibernate会自动执行必要的SQL语句)
        持久(Persistent) - 持久(Persistent)的实例在数据库中有对应的记录,并拥有一个持久化标识(identifier)。 持久(Persistent)的实例可能是刚被保存的,或刚被加载的,无论哪一种,按定义,它存在于相关联的Session作用范围内。 Hibernate会检测到处于持久(Persistent)状态的对象的任何改动,在当前操作单元(unit of work)执行完毕时将对象数据(state)与数据库同步(synchronize)。 开发者不需要手动执行UPDATE。将对象从持久(Persistent)状态变成瞬时(Transient)状态同样也不需要手动执行DELETE语句。
        脱管(Detached) - 与持久(Persistent)对象关联的Session被关闭后,对象就变为脱管(Detached)的。 对脱管(Detached)对象的引用依然有效,对象可继续被修改。脱管(Detached)对象如果重新关联到某个新的Session上, 会再次转变为持久(Persistent)的(在Detached其间的改动将被持久化到数据库)。 这个功能使得一种编程模型,即中间会给用户思考时间(user think-time)的长时间运行的操作单元(unit of work)的编程模型成为可能。 我们称之为应用程序事务,即从用户观点看是一个操作单元(unit of work)。


        好了,进入正题,明白了3种状态,我们来说一下什么时候要用update,什么时候要用merge

        update():如果你确定在当前session的会话里不存在一个与要进行update操作有相同标识符(主键)的持久化对象,那么调用update()。这句话理解起来有点绕,后面举个例子就明白了。

        merge():如果你在任何时候修改了数据都想把数据保存到数据库中,那么就调用merge()。


        例子程序片段:

        有一个Person对象,里面有两个属性,id和name

Session session = sessionFactory.openSession(); 
Transaction tx = session.beginTransaction(); 
Person person = (Person) session.get(Person.class, "15");
tx.commit(); 
session.clear();
session.close();

System.out.println(person.getId());
person.setName("jasper");
Session session2 = sessionFactory.openSession(); 
Transaction tx2 = session2.beginTransaction(); 
Person person2 = (Person) session2.get(Person.class, "15");  //是不是感觉这句代码有点多余,问题就出在这里
//session2.update(person);  //抛出 org.hibernate.NonUniqueObjectException
//session2.saveOrUpdate(person);  //抛出 org.hibernate.NonUniqueObjectException
session2.merge(person);  //成功执行
tx2.commit(); 
session2.close();

        当调用update或saveOrUpdate操作时,抛出了异常信息“org.hibernate.NonUniqueObjectException”,不是“独一无二”的对象。为什么会抛出这个错误呢?上面的person2调用了get方法,所以person2是一个持久化对象,当在session还没有关闭的时候对person2做的任何修改,都会保存到数据库中;person要执行更新操作,但由于它是一个脱管对象,那么就需要跟数据库重新取得联系,需要从数据库获取数据,hibernate会查找当前是否关于这个对象的副本,刚好有个person2(但又不知person2是否修改了且保存到了数据库),与其保存这可能没用的数据,还不如直接报错来得直接。这里调用update和saveOrUpdate类似。

        还有update与merge的一点不同是:update是直接发出“sql update”语句,而merge会先发出“sql select”语句,如果没有查询到结果,那么执行save操作,如果查询到相关结果,则判断对应字段是否有发生改变,如果改变了,则发出“sql update”语句,否则什么也不做。这一方面,merge就和saveOrUpdate相同。


你可能感兴趣的:(Hibernate)