Reattach和Merge操作的比较
Hibernate中将对象从托管状态转变为持久化状态可以采用两种方法:重附(Reattach)和合并(Merge)。下面分别总结一下:
第一种:重附
重附操作使得一个托管对象重新受到persistence context的管理,具体可以采用两种方法:
1. update方法,此方将实体对象从托管状态转变为持久化状态,但是需要注意的是如果当前的持久化上下文(persistence context)中已经存在了一个和托管对象有相同标识符的持久化对象就会抛出NonUniqueException,因为在持久化上下文中,对数据库表中的每一条记录来说,都只能有一个对象与其对应,这样方便持久化对象的脏检测。此方法强制一个update语句,进行持久化对象与数据库的同步。
2. lock方法。lock方法也用与将一个托管对象状态转化为持久化,但是此方法的限制是在确保对象没有被修改的情况下,如果在调用方法之前,修改了对象,那么当事务提交的时候,修改是不会被传播到数据库里的。
第2种:合并
合并就是将托管对象的状态复制到持久化对象里,然后生产一个新的持久化对象。并且合并还有一个作用就是可以将一个transient状态的对象变为persistent状态。在合并操作里,有两种情况:
1. 如果当前的持久化上下文种没有与托管对象相同标识符的对象,那么Hibernate隐式的调用select来查询,如果数据库种有记录,那么就将托管对象的状态与新查询到的对象进行合并,如果数据库没有对应的记录,那么就新建一个持久化对象,然后将托管对象的状态复制到持久化对象里。
2. 如果持久化上下文种有与托管对象相同标识符的对象,那么就将托管对象的状态复制到持久化对象里。(合并中需要注意的是原来托管的对象还是托管的,只不过merge返回的是一个新的持久化对象。)
需要注意的是JPA里只支持合并,不支持重附。
session.merge()方法
该方法将修改表中记录,其所需要的实体状态为脱管状态,但是注意,它并不影响调用方法前后的状态,也即该实体依然是脱管状。
session.merge()方法对状态的变化
public void run() { UserInfo userInfo = new UserInfo(); //创建UserInfo实例 userInfo.setId(11112); //使之成为脱管状态 userInfo.setName("RW3"); userInfo.setSex("M"); UserInfo userInfo2 = new UserInfo(); //创建UserInfo实例 userInfo2.setId(11112); //使之成为脱管状态 userInfo2.setName("RW4"); userInfo2.setSex("F"); Session session = HibernateSessionFactory.currentSession(); //启动Session Transaction tx = session.beginTransaction(); //启动事务 //调用merge方法,此时UserInfo实体状态并没有被持久化,但是数据库中的记录被更新了 session.merge(userInfo); session.merge(userInfo2); //merge方法与update方法的差别在于针对同样的操作update方法会报错 //原因在于update方法使得实体状态成为了持久化状态,而Session中不允许两个持久化实体有同样的持久化标识 //session.update(userInfo); //session.update(userInfo2); //以下两句不会发送SQL,因为userInfo2不是持久化状态的实体 userInfo2.setName("RW5"); userInfo2.setSex("M"); tx.commit(); //提交事务 HibernateSessionFactory.closeSession(); //关闭Hibernate Session}