锁定老帖子 主题:这样的对象是否持久化了呢?
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2004-09-13
Parent p = (Parent); session.load(Parent.class, pid);; session.delete(p);; 这个非常容易理解,将父亲从数据库中读出来,那么这个对象显然已经被持久化了。再删除时,如果配置文件都正确,会进行级联删除。 如果现在我已经有了parent的主键pid,直接去构造一个和数据库查出来的parent类一摸一样的对象p: Parent p = new Parent();; p.setId(pid);; p.setName(name);; ...... 并用上面的一段代码来代替: Parent p = (Parent); session.load(Parent.class, pid);; 同样执行删除操作,Hibernate会报错,并且告诉我有外键的约束。 我不明白的是:对于delete操作,Hibernate到底是如何判别这个Parent对象是否是被持久化过的呢?我直接构造一个和数据库中查出来一样的对象,从外观上看似乎是一致的,但是我也知道,从本质上讲,一定不一样。只是对于Hibernate来说,它到底是如何分辨出这两种不同的对象的呢? 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2004-09-14
通过Parent p = new Parent(); 声明出来的 Parent对象只是处于Transient状态而不是Persistent状态 ,只有在Persistent状态的对象才可以执行delete操作,而用get或load得到的直接就是Persistent状态 的对象,而在Transient状态的对象只有通过 saveOrUpdate或者update才能转换到persistent状态,如果利用上面的new Parent()得到的对象,可能会equal persistent状态的对象,但绝对不是==persistent状态的对象。
|
|
返回顶楼 | |
发表时间:2004-09-14
手动把所有的child都建出来, 这样就能删除了.
Parent p = new Parent(); p.setId(pid); Child c = new Child(); c.setId(cid); p.addChild(c); session.delete(p); Hibernate通过什么来判断一个对象是否被持久化过?? 是id 的 unsaved-value 搜索论坛一下吧, 偶记得Robbin有一篇帖子讲得很清楚的. |
|
返回顶楼 | |
发表时间:2004-09-14
昨天晚上又重新阅读了robbin的两篇大作:《update和saveOrUpdate详解》和《关于unsaved-value的再问》,今天早上又做了一点实验,稍微做一下总结:
引用 在Hibernate中,最核心的概念就是对PO的状态管理。一个PO有三种状态: 1、未被持久化的VO 此时就是一个内存对象VO,由JVM管理生命周期 2、已被持久化的PO,并且在Session生命周期内 此时映射数据库数据,由数据库管理生命周期 3、曾被持久化过,但现在和Session已经detached了,以VO的身份在运行 这种和Session已经detached的PO还能够进入另一个Session,继续进行PO状态管理,此时它就成为PO的第二种状态了。这种PO实际上是跨了Session进行了状态维护的。 在我楼上的这个帖子中,两个不同的删除方法,之所以会不同,就是在于,上面两种删除方法中的PO,分别对应于robbin所说的第一种和第二种状态的PO,因此,只有第二种状态的PO才会被正确删除,而第一种状态的PO不会被认可。 今天早上我尝试了第三种PO的状态。事实证明,PO在第三种状态下,同样可以被正确删除。 ParentDAO dao = new ParentDAOImpl();; Parent p = dao.getParent(pid);; dao.deleteParent(p);; 其中getParent函数和deleteParent都是封装在DAO中的,而我的每个DAO操作都在操作结束后关闭session。显然这个p对象在传入dao.deleteParent(p);时,处于第三种状态。但是在这种情况下,p即使有外键关联,也可以成功的进行级联删除。 总结下来,只要PO的状态是第二种或者第三种,Hibernate都可以成功进行delete和update操作,如果是第一种,那么Hibernate就认为,还没有资格调用上面两种操作。 我现在最大的疑问只是:对于传入dao.deleteParent(p);的这个对象p,Hibernate到底是如何分辨其状态的?毕竟三种状态的对象可以有一摸一样的属性的对应值。 希望大家踊跃讨论。 |
|
返回顶楼 | |
发表时间:2004-09-14
引用 如果是第一种,那么Hibernate就认为,还没有资格调用上面两种操作。 No, a transient instance can be deleted also. check the source code: SessionImpl.delete() |
|
返回顶楼 | |
发表时间:2004-09-14
引用 手动把所有的child都建出来, 这样就能删除了. Parent p = new Parent(); p.setId(pid); Child c = new Child(); c.setId(cid); p.addChild(c); session.delete(p); 经过我的试验,这种方法是不可行的。 引用 Hibernate通过什么来判断一个对象是否被持久化过?? 是id 的 unsaved-value 我认为这句话也是不对的。首先,我的unsaved-value设置为null,而我在新建一个po对象的时候 Parent p = new Parent();; p.setId(pid);; p.setName(name);; ...... 也显然把主键的id设置了进去,它于unsaved-value显然不会相等。这样它就认为这是一个已经被持久化了的对象了?应该不是吧。 引用 如果利用上面的new Parent()得到的对象,可能会equal persistent状态的对象,但绝对不是==persistent状态的对象 不知道这个是什么意思?在没有load一个persistent对象的时候,new出来的对象去和谁比呢? |
|
返回顶楼 | |
发表时间:2004-09-14
引用 手动把所有的child都建出来, 这样就能删除了. Parent p = new Parent(); p.setId(pid); Child c = new Child(); c.setId(cid); p.addChild(c); session.delete(p); 经过试验,这种方法是可行的,为我的不仔细向可敬的Readonly同志道歉。 这样的话,我想我应该明白了,load出来的对象由于每个字段都被load出来,再传入的时候,Hibernate发现它的主键所指的那条记录所对应的对象和传入的完全一致,就认为是一个持久对象。看来它不是只比较一个主键就简单完事了。 谢谢大家的回答,尤其是Readonly,谢谢! |
|
返回顶楼 | |
发表时间:2004-09-14
我的意思是说,如果有下面这样的语句
PO1 a=session.load(PO1.class,id);; PO1 b=session.load(PO1.class,id);; 那么 肯定有a==b 为true 但如果 PO1 c=new PO1();; 则 a==c 肯定为false |
|
返回顶楼 | |
发表时间:2004-09-17
这个贴子质量很高啊.阿扑阿扑
|
|
返回顶楼 | |
发表时间:2004-10-14
Hibernate通过unsaved-value来确定对象是否被持久化过。你完全可以通过自己setId的方式来欺骗Hibernate,让Hibernate认为你new出来的临时对象已经被持久化过。
只不过这样的方式没有太大实际的用途,你也许可以用来写测试。如果你new出来的临时对象是数据库没有的记录,你让Hibernate去操作该记录,只会造成程序运行异常。 总而言之,最好不要自己管理id,而是让Hibernate管理Id,POJO的setId()方法虽然是public的,但那不是开放给你用的,只是开放给Hibernate使用的。我一向认为setId是罪恶的。 |
|
返回顶楼 | |