欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

hibernate merge与update区别

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


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

[color=brown]merge方法打印出的日志如下: [/color]
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=?


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


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

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


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


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

[color=brown]merge方法打印出的日志如下: [/color]
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会把该记录当作新的记录来插入。
[color=olive]
此处我很疑惑,因为我传得person实体对象里写明了id值的,它为什么还会做插入的动作呢?(如果使用不好,则会在更新时,不会更新而是新增一行记录!!!)
在做更新操作时,在merge之前先要持久化一下?
[/color]


[color=brown]update方法打印出的日志如下: [/color]
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


[b]以下的内容摘抄自网上: [/b]

当我们使用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上。

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

[b]谁懂得hibernate的merge方法?[/b]

我使用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