已锁定 主题:POJO 与 PO的 概念
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2003-09-16
PO = persisent object 持久对象 就是说在一些Object/Relation Mapping工具中,能够做到维护数据库表记录的persisent object完全是一个符合Java Bean规范的纯Java对象,没有增加别的属性和方法。全都是这样子的: public class User { private long id; private String name; public void setId(long id); { this.id = id; } public void setName(String name); { this.name=name; } public long getId(); { return id; } public String getName(); { return name; } } --------------------------------------------------------------------------- 首先要区别持久对象和POJO。 持久对象实际上必须对应数据库中的entity,所以和POJO有所区别。比如说POJO是由new创建,由GC回收。但是持久对象是insert数据库创建,由数据库delete删除的。基本上持久对象生命周期和数据库密切相关。另外持久对象往往只能存在一个数据库Connection之中,Connnection关闭以后,持久对象就不存在了,而POJO只要不被GC回收,总是存在的。 由于存在诸多差别,因此持久对象PO(Persistent Object)在代码上肯定和POJO不同,起码PO相对于POJO会增加一些用来管理数据库entity状态的属性和方法。而ORM追求的目标就是要PO在使用上尽量和POJO一致,对于程序员来说,他们可以把PO当做POJO来用,而感觉不到PO的存在。 JDO的实现方法是这样的: 1、编写POJO 2、编译POJO 3、使用JDO的一个专门工具,叫做Enhancer,一般是一个命令行程序,手工运行,或者在ant脚本里面运行,对POJO的class文件处理一下,把POJO替换成同名的PO。 4、在运行期运行的实际上是PO,而不是POJO。 该方法有点类似于JSP,JSP也是在编译期被转换成Servlet来运行的,在运行期实际上运行的是Servlet,而不是JSP。 Hibernate的实现方法比较先进: 1、编写POJO 2、编译POJO 3、直接运行,在运行期,由Hibernate的CGLIB动态把POJO转换为PO。 由此可以看出Hibernate是在运行期把POJO的字节码转换为PO的,而JDO是在编译期转换的。一般认为JDO的方式效率会稍高,毕竟是编译期转换嘛。但是Hibernate的作者Gavin King说CGLIB的效率非常之高,运行期的PO的字节码生成速度非常之快,效率损失几乎可以忽略不计。 实际上运行期生成PO的好处非常大,这样对于程序员来说,是无法接触到PO的,PO对他们来说完全透明。可以更加自由的以POJO的概念操纵PO。另外由于是运行期生成PO,所以可以支持增量编译,增量调试。而JDO则无法做到这一点。实际上已经有很多人在抱怨JDO的编译期Enhancer问题了,而据说JBossDO将采用运行期生成PO字节码,而不采用编译期生成PO字节码。 另外一个相关的问题是,不同的JDO产品的Enhancer生成的PO字节码可能会有所不同,可能会影响在JDO产品之间的可移植性,这一点有点类似EJB的可移植性难题。 ----------------------------------------------------------------------------------- 由这个问题另外引出一个JDO的缺陷。 由于JDO的PO状态管理方式,所以当你在程序里面get/set的时候,实际上不是从PO的实例中取values,而是从JDO StateManager中取出来,所以一旦PM关闭,PO就不能进行存取了。 在JDO中,也可以通过一些办法使得PO可以在PM外面使用,比如说定义PO是transient的,但是该PO在PM关闭后就没有PO identity了。无法进行跨PM的状态管理。 而Hibernate是从PO实例中取values的,所以即使Session关闭,也一样可以get/set,可以进行跨Session的状态管理。 在分多层的应用中,由于持久层和业务层和web层都是分开的,此时Hibernate的PO完全可以当做一个POJO来用,也就是当做一个VO,在各层间自由传递,而不用去管Session是开还是关。如果你把这个POJO序列化的话,甚至可以用在分布式环境中。(不适合lazy loading的情况) 但是JDO的PO在PM关闭后就不能再用了,所以必须在PM关闭前把PO拷贝一份VO,把VO传递给业务层和web层使用。在非分布式环境中,也可以使用ThreadLocal模式确保PM始终是打开状态,来避免每次必须进行PO到VO的拷贝操作。但是不管怎么说,这总是权宜之计,不如Hibernate的功能强。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2006-07-21
说明的非常益懂,谢谢~
|
|
返回顶楼 | |
发表时间:2006-07-24
robbin 写道 由此可以看出Hibernate是在运行期把POJO的字节码转换为PO的,而JDO是在编译期转换的。一般认为JDO的方式效率会稍高,毕竟是编译期转换嘛。但是Hibernate的作者Gavin King说CGLIB的效率非常之高,运行期的PO的字节码生成速度非常之快,效率损失几乎可以忽略不计。
有点不是很明白,是否我通过Middlegen、MyEclipse等工具直接生成的PO也并不是真正的PO,而是POJO,它最终还是会在运行期通过CGLIB自动转化为对用户“透明”的真正的PO呢? |
|
返回顶楼 | |
发表时间:2006-11-27
robbin能否点明:
“...起码PO相对于POJO会增加一些用来管理数据库entity状态的属性和方法。”这个CGLIB生成的是一些什么样的属性和方法? 是否是一些例如version数据版本之类的属性和相应读写方法? 是说CGLIB在运行时不仅读取class字节码而且插入了一些这种持久化相关的属性方法之后才在内存当中实例化PO吗?而因为hibernate是运行时生成所以即使反编译.class也看不到这些插入的东西,而JDO的经过强化的.class文件则可以看到? |
|
返回顶楼 | |
发表时间:2007-04-04
POJO 是无需遵循特定外部接口或第三方 API 的 Java 类。
|
|
返回顶楼 | |
发表时间:2007-04-12
引用 首先要区别持久对象和POJO。
持久对象实际上必须对应数据库中的entity,所以和POJO有所区别。比如说POJO是由new创建,由GC回收。但是持久对象是insert数据库创建,由数据库delete删除的。基本上持久对象生命周期和数据库密切相关。另外持久对象往往只能存在一个数据库Connection之中,Connnection关闭以后,持久对象就不存在了,而POJO只要不被GC回收,总是存在的。 真是长了见识了,以前一直没有想到过它们之间还有差别,谢谢! |
|
返回顶楼 | |
发表时间:2007-04-27
robbin写到:
直接运行,在运行期,由Hibernate的CGLIB动态把POJO转换为PO。 我觉得POJO在运行期通过CGLIB动态解释为一个类似于POJO的东东(我就把认为类似POJO) 类似POJO通过HIBERNATE中本身机制,如,给类似POJO拍下照片后就成了VO . 就想 SINCE1978写道: 这个CGLIB生成的是一些什么样的属性和方法? 是否是一些例如version数据版本之类的属性和相应读写方法? 也就是说CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类. |
|
返回顶楼 | |
发表时间:2007-05-26
robbin 写道 POJO = pure old java object or plain ordinary java object or what ever.
PO = persisent object 持久对象 就是说在一些Object/Relation Mapping工具中,能够做到维护数据库表记录的persisent object完全是一个符合Java Bean规范的纯Java对象,没有增加别的属性和方法。全都是这样子的: public class User { private long id; private String name; public void setId(long id) { this.id = id; } public void setName(String name) { this.name=name; } public long getId() { return id; } public String getName() { return name; } } --------------------------------------------------------------------------- 首先要区别持久对象和POJO。 持久对象实际上必须对应数据库中的entity,所以和POJO有所区别。比如说POJO是由new创建,由GC回收。但是持久对象是insert数据库创建,由数据库delete删除的。基本上持久对象生命周期和数据库密切相关。另外持久对象往往只能存在一个数据库Connection之中,Connnection关闭以后,持久对象就不存在了,而POJO只要不被GC回收,总是存在的。 由于存在诸多差别,因此持久对象PO(Persistent Object)在代码上肯定和POJO不同,起码PO相对于POJO会增加一些用来管理数据库entity状态的属性和方法。而ORM追求的目标就是要PO在使用上尽量和POJO一致,对于程序员来说,他们可以把PO当做POJO来用,而感觉不到PO的存在。 JDO的实现方法是这样的: 1、编写POJO 2、编译POJO 3、使用JDO的一个专门工具,叫做Enhancer,一般是一个命令行程序,手工运行,或者在ant脚本里面运行,对POJO的class文件处理一下,把POJO替换成同名的PO。 4、在运行期运行的实际上是PO,而不是POJO。 该方法有点类似于JSP,JSP也是在编译期被转换成Servlet来运行的,在运行期实际上运行的是Servlet,而不是JSP。 Hibernate的实现方法比较先进: 1、编写POJO 2、编译POJO 3、直接运行,在运行期,由Hibernate的CGLIB动态把POJO转换为PO。 由此可以看出Hibernate是在运行期把POJO的字节码转换为PO的,而JDO是在编译期转换的。一般认为JDO的方式效率会稍高,毕竟是编译期转换嘛。但是Hibernate的作者Gavin King说CGLIB的效率非常之高,运行期的PO的字节码生成速度非常之快,效率损失几乎可以忽略不计。 实际上运行期生成PO的好处非常大,这样对于程序员来说,是无法接触到PO的,PO对他们来说完全透明。可以更加自由的以POJO的概念操纵PO。另外由于是运行期生成PO,所以可以支持增量编译,增量调试。而JDO则无法做到这一点。实际上已经有很多人在抱怨JDO的编译期Enhancer问题了,而据说JBossDO将采用运行期生成PO字节码,而不采用编译期生成PO字节码。 另外一个相关的问题是,不同的JDO产品的Enhancer生成的PO字节码可能会有所不同,可能会影响在JDO产品之间的可移植性,这一点有点类似EJB的可移植性难题。 ----------------------------------------------------------------------------------- 由这个问题另外引出一个JDO的缺陷。 由于JDO的PO状态管理方式,所以当你在程序里面get/set的时候,实际上不是从PO的实例中取values,而是从JDO StateManager中取出来,所以一旦PM关闭,PO就不能进行存取了。 在JDO中,也可以通过一些办法使得PO可以在PM外面使用,比如说定义PO是transient的,但是该PO在PM关闭后就没有PO identity了。无法进行跨PM的状态管理。 而Hibernate是从PO实例中取values的,所以即使Session关闭,也一样可以get/set,可以进行跨Session的状态管理。 在分多层的应用中,由于持久层和业务层和web层都是分开的,此时Hibernate的PO完全可以当做一个POJO来用,也就是当做一个VO,在各层间自由传递,而不用去管Session是开还是关。如果你把这个POJO序列化的话,甚至可以用在分布式环境中。(不适合lazy loading的情况) 但是JDO的PO在PM关闭后就不能再用了,所以必须在PM关闭前把PO拷贝一份VO,把VO传递给业务层和web层使用。在非分布式环境中,也可以使用ThreadLocal模式确保PM始终是打开状态,来避免每次必须进行PO到VO的拷贝操作。但是不管怎么说,这总是权宜之计,不如Hibernate的功能强。 可使用ActiveRecord时应该怎么处理呢?要求从特定的基类继承,好像直接不能作为vo使用吧? |
|
返回顶楼 | |
发表时间:2007-05-28
受教了 谢谢
|
|
返回顶楼 | |
发表时间:2007-05-28
而Hibernate是从PO实例中取values的,所以即使Session关闭,也一样可以get/set,可以进行跨Session的状态管理。
这个不太明白~ |
|
返回顶楼 | |