Reattach和Merge操作的比较

Hibernate中将对象从托管状态转变为持久化状态可以采用两种方法:重附(Reattach)和合并(Merge)。下面分别总结一下:
[b]第一种:重附[/b]
重附操作使得一个托管对象重新受到persistence context的管理,具体可以采用两种方法:
1. update方法,此方将实体对象从托管状态转变为持久化状态,但是需要注意的是如果当前的持久化上下文(persistence context)中已经存在了一个和托管对象有相同标识符的持久化对象就会抛出NonUniqueException,因为在持久化上下文中,对数据库表中的每一条记录来说,都只能有一个对象与其对应,这样方便持久化对象的脏检测。此方法强制一个update语句,进行持久化对象与数据库的同步。
2. lock方法。lock方法也用与将一个托管对象状态转化为持久化,但是此方法的限制是在确保对象没有被修改的情况下,如果在调用方法之前,修改了对象,那么当事务提交的时候,修改是不会被传播到数据库里的。

[b]第2种:合并[/b]
合并就是将托管对象的状态复制到持久化对象里,然后生产一个新的持久化对象。并且合并还有一个作用就是可以将一个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
}


针对该段代码将执行如下SQL语句:
session.merge(userInfo2)的动作:
[color=indigo]select userinfo0_.id as id0_0_, userinfo0_.NAME as NAME0_0_, userinfo0_.SEX as SEX0_0_,
userinfo0_.roomid as roomid0_0_ from userinfo userinfo0_ where userinfo0_.id=?
update userinfo set NAME=?, SEX=?, roomid=? where id=?[/color]
session.merge()方法会首先发送一句select语句,去数据库端获取UserInfo持久化标识所对应的表记录;然后自动生成一个持久化状态的UserInfo实体,与脱管状态的UserInfo实体做比较是否有所改变;一旦发生了改变,才会发送update语句执行更新。而按执行顺序,若两句session.merge()方法针对同一个脱管状态的UserInfo实体,那其结果只会执行最后一个session.merge()方法所发出的update语句。即使执行了session.merge()方法,UserInfo实体依然是脱管状态,因此userInfo2.setName("RW5")的语句不会同步数据库中的表。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值