hibernate merge与update区别

今天做了个测试,写了个测试用例来看看merge与update时控制台打印出来的日志有什么不一样。实体bean很简单,就id和name两个字段,接下来分别给出以下几种测试情形的控制台日志内容:


1. 数据库记录已存在,更改person的name为一个新的name。

merge方法打印出的日志如下:
Hibernate: select person0_.id as id0_0_, person0_.name as name0_0_ from
person person0_ where person0_.id=?
Hibernate: update person set name=?
where id=?


update方法打印出的日志如下:
Hibernate: update person set name=?
where id=?



2. 数据库记录已存在,更改person的name和数据库里对应id记录的name一样的值。

merge方法打印出的日志如下:
Hibernate: select person0_.id as id0_0_,
person0_.name as name0_0_ from person person0_ where person0_.id=?
此处相对于第一种情形少了update的动作


update方法打印出的日志如下:
Hibernate: update person set name=? where id=?



3. 数据库记录不存在。也就是你传的实体bean的ID在数据库没有对应的记录。

merge方法打印出的日志如下:
Hibernate: select person0_.id as id0_0_, person0_.name as name0_0_
from person person0_ where person0_.id=?
Hibernate: insert into person (name) values (?)

如果没有对应的记录,merge会把该记录当作新的记录来插入。

此处我很疑惑,因为我传得person实体对象里写明了id值的,它为什么还会做插入的动作呢?(如果使用不好,则会在更新时,不会更新而是新增一行记录!!!)
在做更新操作时,在merge之前先要持久化一下?



update方法打印出的日志如下:
Hibernate: update person set name=? where id=?

2009-11-22 20:59:55,359 ERROR [org.hibernate.jdbc.AbstractBatcher] -
Exception executing batch:
org.hibernate.StaleStateException: Batch update
returned unexpected row count from update [0]; actual row count: 0; expected: 1



以下的内容摘抄自网上:

当我们使用update的时候,执行完成后,我们提供的对象A的状态变成持久化状态。

当我们使用merge的时候,执行完成后,我们提供的对象A还是脱管状态。hibernate或者是new了一个B(此时执行插入操作),或者检索到一个持久对象B(此时执行更新操作),并把我们提供的对象A的所有的值拷贝到这个B,执行完成后B是持久状态,而我们提供的A还是托管状态。


----------------------------------

使用merge方法,如果数据库中有该记录,则更新该记录,如果不存在该记录,则进行insert操作。

使用update的话,会无条件执行update。

也就是说如果数据库中有该记录的话,merge和update是一样的。
但是如果数据库中没有该记录,使用merge执行insert,不会报错,而使用update会报错。


不同之处在于,update可以持久化类,merge不行 --- 重要

---------------------------------------

假设有个Student stu类,session.update(stu),merge也是一样。
不同之处在于,update可以持久化类,merge不行,执行session.merge(stu)之后,stu对象如果之前不是持久化状态,stu对象依然不会被关联到session上。

----------------------------------------

谁懂得hibernate的merge方法?

我使用merge方法。老是报could not load an entity的异常。
配置文件,一定没有问题。
于是,我写了个junit的单元测试。这个单元测试继承了HibernateDaoSupport,并注入了sessionFactory,并调用
this.getHibernateTemplate.merge 方法,还是could not load an entity.

是我对merge理解有问题,还是其他什么问题?

//单元测试如下

public class MergeTest extends HibernateDaoSupport {

@Test
public void testMerge(){

//获取spring配置
ApplicationContext act = new FileSystemXmlApplicationContext("/WebRoot/WEB-INF/applicationContext.xml");

//注入sesssionFactory
this.setSessionFactory((SessionFactory)act.getBean("sessionFactory"));

//创建一个模拟的DocumentCatalog 数据中已经有个 id = 1的数据
DocumentCatalog dc = new DocumentCatalog();

dc.setId(1);
dc.setName("crying!!!!!");

//我认为,这时候,数据库中的 id = 1的数据,会被update,但是,发生could not load an entity错误。
//数据库映射没有错误,换成update就能顺利更新。
this.getHibernateTemplate().merge(dc);

}
}


用update是直接把实体和数据库同步,而是要merge方法时 merge操作的是实体的代理对象,所以我们用它时一定要把它放到事务中执行,否则会报could not load an entity异常,
意思是在:this.getHibernateTemplate().merge(dc);语句前面开启一个事务就OK




=========================================================

理一下思路:(没有验证)

使用merge方法时,
如果存在一个持久化的对象,则执行 update 操作。
如果不存在一个持久化的对象,则进行插入操作。

所以,对象需要先持久化后,再进行 merge() 。这里的持久化不是数据库中是否有这条记录,而是 Hibernate 中数据的状态。如果数据库中存在一条记录,而没有被 Hibernate 持久化,使用 merge() 时,仍然执行的是新增一条记录操作。而不是更新操作。












-
引用:
http://www.cnblogs.com/hyteddy/archive/2011/05/10/2041762.html

猜你喜欢

转载自lixh1986.iteye.com/blog/2369861