`

hibernate的保存

阅读更多

hibernate的保存
hibernate对于对象的保存提供了太多 的方法,他们之间有很多不同,这里细说一下,以便区别:
一、预备知识:
在所有之前,说明一下,对于hibernate,它的对象有三种状 态,transient、persistent、detached
下边是常见的翻译办法:
transient:瞬态或者自由态
persistent: 持久化状态
detached:脱管状态或者游离态

脱管状态的实例可以通过调用save()、persist()或者 saveOrUpdate()方法进行持久化。
持久化实例可以通过调用 delete()变成脱管状态。通过get()或load()方法得到的实例都是持久化状态的。
脱管状态的实例可以通过调用 update()、0saveOrUpdate()、lock()或者replicate()进行持久化。

save()和persist()将会引发SQL的 INSERT,delete()会引发SQLDELETE,
而update()或merge()会引发SQLUPDATE。对持久化 (persistent)实例的修改在刷新提交的时候会被检测到,
它也会引起SQLUPDATE。saveOrUpdate()或者 replicate()会引发SQLINSERT或者UPDATE

二、save 和update区别
把这一对放在第一位的原因是因为这一 对是最常用的。
save的作用是把一个新的对象保存
update是把一个脱管状态的对象保存

三,update 和saveOrUpdate区别
这个是比较好理解 的,顾名思义,saveOrUpdate基本上就是合成了save和update
引用hibernate reference中的一段话来解释他们的使用场合和区别
通常下面的场景会使用update()或saveOrUpdate():
程序 在第一个session中加载对象
该对象被传递到表现层
对象发生了一些改动
该对象被返回到业务逻辑层
程序调用第 二个session的update()方法持久这些改动

saveOrUpdate()做下面的事:
如果对象已经在本 session中持久化了,不做任何事
如果另一个与本session关联的对象拥有相同的持久化标识(identifier),抛出一个异常
如 果对象没有持久化标识(identifier)属性,对其调用save()
如果对象的持久标识(identifier)表明其是一个新实例化的 对象,对其调用save()
如果对象是附带版本信息的(通过<version>或<timestamp>) 并且版本属性的值表明其是一个新实例化的对象,save()它。
否则update() 这个对象

四,persist和save区别
这个是最迷离的一对,表面上看起来使 用哪个都行,在hibernate reference文档中也没有明确的区分他们.
这里给出一个明确的区分。(可以跟进src看一下,虽然实现 步骤类似,但是还是有细微的差别)
这里参考
http://opensource.atlassian.com/projects/hibernate/browse/HHH-1682 中的一个说明:
---------------------------------------------------------------------------------
I found that a lot of people have the same doubt. To help to solve this issue
I'm quoting Christian Bauer:
"In case anybody finds this thread...

persist() is well defined. It makes a transient instance persistent. However,
it doesn't guarantee that the identifier value will be assigned to the persistent
instance immediately, the assignment might happen at flush time. The spec doesn't say
that, which is the problem I have with persist().

persist() also guarantees that it will not execute an INSERT statement if it is
called outside of transaction boundaries. This is useful in long-running conversations
with an extended Session/persistence context.A method like persist() is required.

save() does not guarantee the same, it returns an identifier, and if an INSERT
has to be executed to get the identifier (e.g. "identity" generator, not "sequence"),
this INSERT happens immediately, no matter if you are inside or outside of a transaction. This is not good in a long-running conversation with an extended Session/persistence context."

---------------------------------------------------------------------------------
简 单翻译一下上边的句子的主要内容:
1,persist把一个瞬态的实例持久化,但是并"不保证"标识符被立刻填入到持久化实例中,标识符的填入可 能被推迟
到flush的时间。

2,persist"保证",当它在一个transaction外部被调用的时 候并不触发一个Sql Insert,这个功能是很有用的,
当我们通过继承Session/persistence context来封装一个长会话流程的时候,一个persist这样的函数是需要的。

3,save"不保证"第2条,它要返回标识符,所以它会立即执行Sql insert,不管是不是在transaction内部还是外部


五,saveOrUpdateCopy,merge和update区别
首 先说明merge是用来代替saveOrUpdateCopy的,这个详细见这里
http://www.blogjava.net/dreamstone/archive/2007/07/28/133053.html
然后比较update和merge
update的作用上边说了,这里说一下merge的
如 果session中存在相同持久化标识(identifier)的实例,用用户给出的对象的状态覆盖旧有的持久实例
如果session没有相应 的持久实例,则尝试从数据库中加载,或创建新的持久化实例,最后返回该持久实例
用户给出的这个对象没有被关联到session上,它依旧是脱管 的
重点是最后一句:
当我们使用update的时候,执行完成后,我们提供的对象A的状态变成持久化状态
但当我们使用merge 的时候,执行完成,我们提供的对象A还是脱管状态,hibernate或者new了一个B,或者检索到
一个持久对象B,并把我们提供的对象A的所 有的值拷贝到这个B,执行完成后B是持久状态,而我们提供的A还是托管状态

六,flush和update区别
这两个的区别好理解
update 操作的是在脱管状态的对象
而flush是操作的在持久状态的对象。
默认情况下,一个持久状态的对象是不需要update的,只要你更改了 对象的值,等待hibernate flush就自动
保存到数据库了。hibernate flush发生再几种情况下:
1,调用某些查 询的时候
2,transaction commit的时候
3,手动调用flush的时候

七,lock和update区别
update是把一个已经更改过的脱管 状态的对象变成持久状态
lock是把一个没有更改过的脱管状态的对象变成持久状态
对应更改一个记录的内容,两个的操作不同:
update 的操作步骤是:
(1)更改脱管的对象->调用update
lock的操作步骤是:
(2)调用lock把对象从脱管状态变成 持久状态-->更改持久状态的对象的内容-->等待flush或者手动flush

参考内容:
http://www.blogjava.net/iamtin/archive/2006/03/06/33910.aspx
http://opensource.atlassian.com/projects/hibernate/browse/HHH-1682
http://www.redsaga.com/hibernate-ref/3.x/zh-cn/html/objectstate.html

 

 

 

 

 

 

先来点概念:
在Hibernate中,最核心的概念就是对PO的状态管理。一个PO有三种状 态:
1、未被持久化的VO
此时就是一个内存对象VO,由JVM管理生命周期
2、已被持久化的PO,并且在Session生命周期内
此时映射数据库数据,由数据库管理生命周期
 
3、曾被持久化过,但现在和Session已经detached了,以VO的身 份在运行
这种和Session已经detached的PO还能够进入另一个 Session,继续进行PO状态管理,此时它就成为PO的第二种状态了。这种PO实际上是跨了Session进行了状态维护的。
在传统的JDO1.x中,PO只有前面两种状态,一个PO一旦脱离PM,就丧失 了状态了,不再和数据库数据关联,成为一个纯粹的内存VO,它即使进入一个新的PM,也不能恢复它的状态了。
Hibernate强的地方就在于,一个PO脱离Session之后,还能保持 状态,再进入一个新的Session之后,就恢复状态管理的能力,但此时状态管理需要使用session.update或者 session.saveOrUpdate,这就是Hibernate Reference中提到的“requires a slightly different programming model ”
 
现在正式进入本话题:
简单的来说,update和saveOrUpdate是用来对跨Session 的PO进行状态管理的。
假设你的PO不需要跨Session的话,那么就不需要用到,例如你打开一个 Session,对PO进行操作,然后关闭,之后这个PO你也不会再用到了,那么就不需要用update。
因此,我们来看看:
代码
Foo foo=sess.load(Foo.class,id);   
foo.setXXX(xxx);   
sess.flush();  
sess.commit();  
PO 对象 foo 的操作都在一个 Session 生命周期内完成,因此不需要显式的进行 sess.update(foo) 这样的操作。 Hibernate 会自动监测到 foo 对象已经被修改过,因此就向数据库发送一个 update sql 。当然如果你非要加上 sess.update(foo) 也不会错,只不过这样做没有任何必要。
而 跨 Session 的意思就是说这个 PO 对象在 Session 关闭之后,你还把它当做一个 VO 来用,后来你在 Session 外面又修改了它的属 性,然后你又想打开一个 Session ,把 VO 的属性修改保存到数据库里面,那么你就需 要用 update 了。
代码
// in the first session   
Cat cat = (Cat) firstSession.load(Cat.class, catId);   
Cat potentialMate = new Cat();   
firstSession.save(potentialMate);   
 
// in a higher tier of the application   
potentialMate.setXxx(xxx);
cat.setMate(potentialMate);   
 
// later, in a new session   
secondSession.update(cat); // update cat   
secondSession.update(mate); // update mate 
 
cat和mate对象是在第一个session中取得的,在第一个 session关闭之后,他们就成了PO的第三种状态,和Session已经detached的PO,此时他们的状态信息仍然被保留下来了。当他们进入第 二个session之后,立刻就可以进行状态的更新。但是由于对cat的修改操作:cat.setMate(potentialMate); 是在Session外面进行的,Hibernate不可能知道cat对象已经被改过了,第二个Session并不知道这种修改,因此一定要显式的调用 secondSession.update(cat); 通知Hibernate,cat对象已经修改了,你必须发送update的sql了。
 
所以update的作用就在于此,它只会被用于当一个PO对象跨Session 进行状态同步的时候才需要写。而一个PO对象当它不需要跨Session进行状态管理的时候,是不需要写update的。
 
再谈谈saveOrUpdate的用场:
saveOrUpdate update 的区别就在于在跨 Session PO 状态管理中, Hibernate PO 采取何种策略。
 
例如当你写一个DAOImpl的时候,让cat对象增加一个mate,如下定 义:
代码
public void addMate(Cat cat, Mate mate) {  
    Session session = ...;  
    Transacton tx = ...;  
    session.update(cat);  
    cat.addMate(mate);  
    tx.commit();  
    session.close();  
}; 
 
显然你是需要把Hibernate的操作封装在DAO里面的,让业务层的程序员 和Web层的程序员不需要了解Hibernate,直接对DAO进行调用。
 
此时问题就来了:上面的代码运行正确有一个必要的前提,那就是方法调用参数 cat对象必须是一个已经被持久化过的PO,也就是来说,它应该首先从数据库查询出来,然后才能这样用。但是业务层的程序员显然不知道这种内部的玄妙,如 果他的业务是现在增加一个cat,然后再增加它的mate,他显然会这样调用,new一个cat对象出来,然后就addMate:
 
代码
Cat cat = new Cat();  
cat.setXXX();  
daoimpl.addMate(cat,mate); 
 
但 是请注意看,这个 cat 对象只是一个 VO ,它没有被持久化过,它还不是 PO ,它没有资格调用 addMate 方法,因此调用 addMate 方法不会真正往数据库 里面发送 update sql ,这个 cat 对象必须先被 save 到数据库,在真正成为一个 PO 之后,才具备 addMate 的资格。
 
你必须这样来操作:
 
 
代码
Cat cat = new Cat();  
cat.setXXX();  
daoimpl.addCat(cat);  
daoimpl.addMate(cat, mate); 
 
先持久化cat,然后才能对cat进行其他的持久化操作。因此要求业务层的程序 员必须清楚cat对象处于何种状态,到底是第一种,还是第三种。如果是第一种,就要先save,再addMate;如果是第三种,就直接addMate。
 
但是最致命的是,如果整个软件分层很多,业务层的程序员他拿到这个cat对象也 可能是上层Web应用层传递过来的cat,他自己也不知道这个cat究竟是VO,没有被持久化过,还是已经被持久化过,那么他根本就没有办法写程序了。
 
所以这样的DAOImpl显然是有问题的,它会对业务层的程序员造成很多编程上 的陷阱,业务层的程序员必须深刻的了解他调用的每个DAO对PO对象进行了何种状态管理,必须深刻的了解他的PO对象在任何时候处于什么确切的状态,才能 保证编程的正确性,显然这是做不到的,但是有了saveOrUpdate,这些问题就迎刃而解了。
 
现在你需要修改addMate方法:
代码
public void addMate(Cat cat, Mate mate) {  
    Session session = ...;  
    Transacton tx = ...;  
    session.saveOrUpdate(cat);  
    cat.addMate(mate);  
    tx.commit();  
    session.close();  
}; 
 
如上,如果业务层的程序员传进来的是一个已经持久化过的PO对象,那么 Hibernate会更新cat对象(假设业务层的程序员在Session外面修改过cat的属性),如果传进来的是一个新new出来的对象,那么向数据 库save这个PO对象。
 
BTW: Hibernate此时究竟采取更新cat对象,还是save cat对象,取决于unsave-value的设定。
 
这样,业务层的程序员就不必再操心PO的状态问题了,对于他们来说,不管cat 是new出来的对象,只是一个VO也好;还是从数据库查询出来的的PO对象也好,全部都是直接addMate就OK了:
代码
daoimple.addMate(cat, mate); 
这便是saveOrUpdate的作用。
 
使 用 get() load() 方法取得 id 1 的数据 ;
如 果未能发现相符合的数据,则 get() 方法会返回 null ,而 load() 方法会丢出 ObjectNotFoundException ,在进阶的应用中, load() 方法可以返 回代理对象,并可充分利用缓冲机制。

Hibernate 3 中,取消了 find() 方法,您必须透过 Query Criteria 来进行数据查询

分享到:
评论

相关推荐

    hibernate保存不到数据1

    标题中的"hibernate保存不到数据1"是一个关于Hibernate框架在尝试保存数据到数据库时遇到问题的场景。描述提到了一个具体的解决方案,即通过在`hibernate.cfg.xml`配置文件中设置`connection.autocommit`属性为`true...

    hibernate保存blob,clob对象

    这篇文章将详细讲解如何在Hibernate中保存这两种特殊类型的数据。 BLOB用于存储二进制大对象,如图片、音频或视频文件等;而CLOB则用于存储字符型的大数据,例如长文本、XML文档等。在Java中,Blob和Clob是JDBC API...

    hibernate保存图片

    ### Hibernate保存图片知识点详解 #### 一、引言 在Web开发中,处理用户上传的图片是一项常见的需求。本文档将详细介绍如何利用Hibernate框架将图片数据直接存储到数据库的Blob字段中。通过这种方式,可以避免在...

    Hibernate下数据批量处理解决方案

    在Java开发中,尤其是涉及到大数据量的处理时,人们往往会质疑ORM框架,如Hibernate,是否适合进行批量数据操作。然而,实际上,通过适当的技术手段,我们可以有效地解决Hibernate在批量处理时可能出现的性能问题。...

    hibernate

    4. **持久化类(Persistent Class)**:持久化类是具有持久性状态的实体类,它们的状态可以通过Hibernate保存到数据库中。Hibernate使用注解或XML配置文件来定义字段与数据库列的映射。 5. **ID生成策略**:每个...

    hibernate_second项目源码

    项目中的源码将展示如何使用Hibernate保存、更新、查询和删除数据。这包括了如何添加新的关联对象,如何更新已存在的关联,以及如何查询和删除数据。 通过详细研究**hibernate_second**项目,开发者不仅可以掌握...

    Hibernate主键生成方式

    当Hibernate保存一个新实体时,数据库会自动为该实体分配一个新的唯一值。这种方式适用于那些支持自动增长字段的数据库,如MySQL和SQL Server。 2. **Increment方式**:`&lt;generator class="increment"/&gt;` 这种方式...

    Hibernate 的第一个例子

    这个简单的例子展示了如何使用Hibernate保存一个新用户到数据库。进一步学习时,你可以尝试查询、更新和删除操作,以及更复杂的查询表达式。 **总结** 通过这个"Hibernate的第一个例子",我们了解了如何配置...

    Hibernate 使用缓存时,数据同步问题

    当一个实体被加载到Session时,其状态会保存在一级缓存中,以便后续操作能够快速访问,无需再次查询数据库。一级缓存在Session关闭或清空时失效。 - **二级缓存**:在SessionFactory级别共享,用于跨Session存储...

    从头到脚跟你解释什么是Hibernate - renco的专栏

    在大多数情况下,修改对象的状态只需在程序中直接操作,然后通过Hibernate保存更改。 Hibernate的API学习曲线平缓,它无缝融入程序流程,使得数据库操作更加自然。此外,Hibernate的数据库无关性也是一个显著优点,...

    Struts2+hibernate示例

    8. **集成测试**:完成上述配置后,开发者通常会编写一些测试用例来验证Struts2和Hibernate的整合是否正确,比如创建一个新的实体对象,通过Hibernate保存到数据库,然后通过Struts2的Action查询并展示出来。...

    hibernate 简单工程

    在`hibernate_0001_helloWorld`这个子目录中,可能包含了一个简单的HelloWorld示例,展示了如何使用Hibernate保存和查询数据。这个示例通常包括一个简单的实体类、一个对应的数据库表、以及一些基本的保存和查询操作...

    oracle+hibernate 处理blob +uploadify实例

    `uploadImg`方法会解析`HttpServletRequest`,找到上传的文件,然后将文件内容读取到内存或磁盘,最后通过Hibernate保存到Oracle数据库中。具体实现通常会涉及到解析文件项,获取文件内容,创建`Learner`对象并调用...

    用myeclipse自动生成hibernate配置文件

    这个测试类会创建一个新的`Guestbook`对象,并通过Hibernate保存到数据库中。运行这个测试,如果一切配置正确,数据将被成功插入到`guestbook`表中。 通过以上步骤,利用MyEclipse的自动生成功能,我们可以快速地...

    基于Java+hibernate的聊天系统

    4. **数据库管理**:通过Hibernate保存和查询用户信息、聊天记录等数据。 5. **网络通信**:使用Socket编程或者HTTP协议实现客户端与服务器之间的实时通信。 在文件"qq1.0"中,可能包含了项目的源代码、配置文件、...

    jsp+struts+spring+hibernate新闻系统

    1. **新闻添加**:用户或管理员可以通过表单提交新闻标题、内容、类别等信息,这些信息通过Struts Action被传递到后台服务,然后由Hibernate保存到数据库。 2. **新闻删除**:系统提供接口供用户或管理员选择并删除...

    Hibernate 帮助手册 API

    4. **持久化类和标识符**:持久化类是具有持久状态的Java类,其实例可以通过Hibernate保存到数据库。每个持久化类都需要一个唯一的标识符(ID),这通常由`@Id`注解标记的属性表示。 5. **关联映射**:Hibernate...

    struts+hibernate的一个房屋出租系统网站

    - **注册**:用户填写基本信息并提交,Struts框架接收请求,调用对应的Action,验证数据,通过Hibernate保存到数据库。 - **登录**:用户输入账号和密码,后台验证后,如果成功,将用户信息存储在session中,以便...

Global site tag (gtag.js) - Google Analytics