POJO = pure old java object or plain ordinary java object or what ever.
PO = persisent object 持久對象
就是說(shuō)在一些Object/Relation Mapping工具中,能夠做到維護數據庫表記錄的persisent object完全是一個(gè)符合Java Bean規范的純Java對象,沒(méi)有增加別的屬性和方法。全都是這樣子的:
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。
持久對象實(shí)際上必須對應數據庫中的entity,所以和POJO有所區別。比如說(shuō)POJO是由new創(chuàng )建,由GC回收。但是持久對象是insert數據庫創(chuàng )建,由數據庫delete刪除的?;旧铣志脤ο笊芷诤蛿祿烀芮邢嚓P(guān)。另外持久對象往往只能存在一個(gè)數據庫Connection之中,Connnection關(guān)閉以后,持久對象就不存在了,而POJO只要不被GC回收,總是存在的。
由于存在諸多差別,因此持久對象PO(Persistent Object)在代碼上肯定和POJO不同,起碼PO相對于POJO會(huì )增加一些用來(lái)管理數據庫entity狀態(tài)的屬性和方法。而ORM追求的目標就是要PO在使用上盡量和POJO一致,對于程序員來(lái)說(shuō),他們可以把PO當做POJO來(lái)用,而感覺(jué)不到PO的存在。
JDO的實(shí)現方法是這樣的:
1、編寫(xiě)POJO
2、編譯POJO
3、使用JDO的一個(gè)專(zhuān)門(mén)工具,叫做Enhancer,一般是一個(gè)命令行程序,手工運行,或者在ant腳本里面運行,對POJO的class文件處理一下,把POJO替換成同名的PO。
4、在運行期運行的實(shí)際上是PO,而不是POJO。
該方法有點(diǎn)類(lèi)似于JSP,JSP也是在編譯期被轉換成Servlet來(lái)運行的,在運行期實(shí)際上運行的是Servlet,而不是JSP。
Hibernate的實(shí)現方法比較先進(jìn):
1、編寫(xiě)POJO
2、編譯POJO
3、直接運行,在運行期,由Hibernate的CGLIB動(dòng)態(tài)把POJO轉換為PO。
由此可以看出Hibernate是在運行期把POJO的字節碼轉換為PO的,而JDO是在編譯期轉換的。一般認為JDO的方式效率會(huì )稍高,畢竟是編譯期轉換嘛。但是Hibernate的作者Gavin King說(shuō)CGLIB的效率非常之高,運行期的PO的字節碼生成速度非常之快,效率損失幾乎可以忽略不計。
實(shí)際上運行期生成PO的好處非常大,這樣對于程序員來(lái)說(shuō),是無(wú)法接觸到PO的,PO對他們來(lái)說(shuō)完全透明??梢愿幼杂傻囊訮OJO的概念操縱PO。另外由于是運行期生成PO,所以可以支持增量編譯,增量調試。而JDO則無(wú)法做到這一點(diǎn)。實(shí)際上已經(jīng)有很多人在抱怨JDO的編譯期Enhancer問(wèn)題了,而據說(shuō)JBossDO將采用運行期生成PO字節碼,而不采用編譯期生成PO字節碼。
另外一個(gè)相關(guān)的問(wèn)題是,不同的JDO產(chǎn)品的Enhancer生成的PO字節碼可能會(huì )有所不同,可能會(huì )影響在JDO產(chǎn)品之間的可移植性,這一點(diǎn)有點(diǎn)類(lèi)似EJB的可移植性難題。
由這個(gè)問(wèn)題另外引出一個(gè)JDO的缺陷。
由于JDO的PO狀態(tài)管理方式,所以當你在程序里面get/set的時(shí)候,實(shí)際上不是從PO的實(shí)例中取values,而是從JDO State Manager?中取出來(lái),所以一旦PM關(guān)閉,PO就不能進(jìn)行存取了。
在JDO中,也可以通過(guò)一些辦法使得PO可以在PM外面使用,比如說(shuō)定義PO是transient的,但是該PO在PM關(guān)閉后就沒(méi)有PO identity了。無(wú)法進(jìn)行跨PM的狀態(tài)管理。
而Hibernate是從PO實(shí)例中取values的,所以即使Session關(guān)閉,也一樣可以get/set,可以進(jìn)行跨Session的狀態(tài)管理。
在分多層的應用中,由于持久層和業(yè)務(wù)層和web層都是分開(kāi)的,此時(shí)Hibernate的PO完全可以當做一個(gè)POJO來(lái)用,也就是當做一個(gè)VO,在各層間自由傳遞,而不用去管Session是開(kāi)還是關(guān)。如果你把這個(gè)POJO序列化的話(huà),甚至可以用在分布式環(huán)境中。(不適合lazy loading的情況)
但是JDO的PO在PM關(guān)閉后就不能再用了,所以必須在PM關(guān)閉前把PO拷貝一份VO,把VO傳遞給業(yè)務(wù)層和web層使用。在非分布式環(huán)境中,也可以使用ThreadLocal模式確保PM始終是打開(kāi)狀態(tài),來(lái)避免每次必須進(jìn)行PO到VO的拷貝操作。但是不管怎么說(shuō),這總是權宜之計,不如Hibernate的功能強。
辨別一些名詞:
1。VO:實(shí)際上很模糊,通常指ValueObject和ViewObject
2. ViewObject,界面展現需要的對象,如Struts的FormBean
3。Value Object,早期被作為ValueObject和Transfer Object的總稱(chēng)。實(shí)際上Value Object的真正意義在于它的內容,而不是身份
4。Transfer Object:數據傳輸對象,在應用程序不同層次之間傳書(shū)對象,在一個(gè)分布式應用程序中,通??梢蕴岣哒w的性能
5。PO:也許就是Persistent Object,基本上就是Entity了
在不同的體系結構和實(shí)現方式里面,這些對象有可能重復,也有可能不重疊。如果你要做一個(gè)對所有的體系都能夠方便移植的框架,那么每一種對象都需要嚴格區分。例如JDO的PO不能作為T(mén)O,應為它不能脫離PM,譬如你可以選擇用ViewObject(如Struts的FOrmBean)直接作為T(mén)O,但在tapestry和Webwork里面就不合適了。但在很多時(shí)候,能夠方便實(shí)用是最重要的,不要過(guò)度設計就是了。
POJO是這樣一個(gè)對象,它是一個(gè)普通的Java對象,它不同于EJB這樣的帶有繁重的容器控制功能的對象,它也不是那種被Enhanced過(guò)的對象,例如JDO的靜態(tài)Enhance,也不是類(lèi)似Hibernate那樣被動(dòng)態(tài)的byte code generation過(guò)。
也就是說(shuō)POJO的概念是相對于其他那種被人動(dòng)過(guò)手腳的class而言的,它是沒(méi)有被動(dòng)過(guò)手腳的。
其實(shí),為什么要做DAO?無(wú)非是:
1, 管理connection/transaction (hibernate的話(huà)就是session/transaction)
2, 便于進(jìn)行統計/log操作;
3, 便于進(jìn)行權限控制;
DAO模式中,有兩類(lèi)對象,一種是DAO,一種是valueObject。 在我們討論的這個(gè)情況中,value object是hibernate對應的POJO.
那么,按照我的理解,DAO就是一個(gè)Transaction包裝器,其邏輯結構就是商業(yè)的具體事務(wù)。此處,數據庫的transaction和商業(yè)的事務(wù)是統一的。
聯(lián)系客服