love fish大鵬一曰同風(fēng)起,扶搖直上九萬(wàn)里

          常用鏈接

          統(tǒng)計(jì)

          積分與排名

          friends

          link

          最新評(píng)論

          EJB3.0之介紹Entity(轉(zhuǎn))

          EJB3介紹:Overview

          EJB作為企業(yè)級(jí)的數(shù)據(jù)訪問(wèn)/持久化標(biāo)準(zhǔn)在1999年作為J2EE規(guī)范的核心規(guī)范出現(xiàn),極大的轉(zhuǎn)變了java企業(yè)級(jí)開(kāi)發(fā)的模式,為java軟件開(kāi)發(fā)提供了一個(gè)良好的架構(gòu)。 EJB從1.0到2.1在J2EE架構(gòu)中,都是作為一個(gè)服務(wù)器端的(Server side)的數(shù)據(jù)訪問(wèn)中間件。開(kāi)發(fā)人員通過(guò)EJB標(biāo)準(zhǔn)的API接口來(lái)訪問(wèn)操作數(shù)據(jù),避免直接用JDBC和Sql操作底層的數(shù)據(jù)庫(kù)。

          采用EJB架構(gòu)的目標(biāo)在于:

          • 減輕直接操作底層數(shù)據(jù)庫(kù)的工作量
          • 為企業(yè)級(jí)開(kāi)發(fā)引入了面向?qū)ο?面向服務(wù)的開(kāi)發(fā)架構(gòu)
          • 數(shù)據(jù)對(duì)象生命周期的自動(dòng)管理
          • 分布式能力
          • 集成/聲明式的安全/事務(wù)管理

          在舊的EJB模型中(2.1以前),EJB實(shí)現(xiàn)了大部分的目標(biāo),但一個(gè)巨大的缺陷是原有的模型在試圖減輕數(shù)據(jù)訪問(wèn)工作量的同時(shí)也引入了更多的復(fù)雜開(kāi)發(fā)需求。 例如EJB核心的的Entity Bean必須特定的Home,Remote,Business接口,發(fā)布前需要預(yù)編譯,只能實(shí)現(xiàn)單表映射操作,靜態(tài)的EJB-QL(EJB查詢語(yǔ)言)都不能滿足簡(jiǎn)化數(shù)據(jù)庫(kù)操作的目標(biāo)。 EJB 2.1的復(fù)雜度,開(kāi)發(fā)成本和性能問(wèn)題使得EJB在問(wèn)世4年后仍然等不到廣泛的應(yīng)用。

          到了2004年,隨著POJO( Plain Old Java Object )模型的出現(xiàn),動(dòng)態(tài)代碼操作,IOC模式等先進(jìn),簡(jiǎn)單實(shí)用技術(shù)的發(fā)展和它們?cè)诟鞣N獨(dú)立產(chǎn)品中的表現(xiàn),都證明POJO,IOC的技術(shù)比原有的EJB 2.1模型更適合作為數(shù)據(jù)訪問(wèn)中間件,開(kāi)發(fā)的難度和成本遠(yuǎn)遠(yuǎn)小于目前的EJB模型,確有更靈活和可擴(kuò)展。 2004年9月J2EE平臺(tái)規(guī)范集眾家所長(zhǎng),推出了跨越式的Java EE 5.0規(guī)范,最核心的是全面引入新的基于POJO和IOC技術(shù)的EJB3模型。到此,J2EE 5規(guī)范( Java EE 5 )成為一個(gè)集大成者,納百家之長(zhǎng),成為java企業(yè)開(kāi)發(fā)統(tǒng)一的標(biāo)準(zhǔn)規(guī)范。

          EJB 3和EJB 2.1的區(qū)別

          從整個(gè)EJB規(guī)范的角度來(lái)說(shuō),EJB 3和EJB 2.1最大變更在Entity Bean持久化API上。在EJB3中,Entity Bean持久化已經(jīng)單獨(dú)作為一個(gè)Persistence API規(guī)范和其他的EJB部分分離開(kāi)來(lái)。下面我們主要討論EJB 3和EJB 2.1在持久化API上的區(qū)別。

          EJB 2.1模型存在復(fù)雜度高的缺陷:

          • EJB 2.0 模型要求創(chuàng)建多個(gè)組件接口并實(shí)現(xiàn)多個(gè)不必要的回調(diào)方法
          • 組件接口要求實(shí)現(xiàn) EJBObject 或 EJBLocalObject 以及處理許多不必要的異常
          • 基于XML的EJB 2.0 部署描述符比較復(fù)雜并容易出錯(cuò)
          • 基于 EJB 模型的容器管理持久性在開(kāi)發(fā)和管理方面過(guò)于復(fù)雜,并且失去了幾個(gè)基本特性--如使用數(shù)據(jù)庫(kù)序列定義主鍵的標(biāo)準(zhǔn)方法
          • EJBQL 語(yǔ)法非常有限,而且是靜態(tài)的,無(wú)法做到運(yùn)行期間的動(dòng)態(tài)查詢
          • EJB 2.0 組件并非是真正面向?qū)ο蟮?,因?yàn)樗鼈冊(cè)诶^承和多態(tài)性方面的有使用限制
          • 開(kāi)發(fā)人員無(wú)法在 EJB 容器外部測(cè)試 EJB 模塊,而在容器內(nèi)部調(diào)試 EJB非常復(fù)雜和耗時(shí)
          • 查找和調(diào)用 EJB 2.0 是一項(xiàng)復(fù)雜的任務(wù)。即使是在應(yīng)用程序中使用最基本的 EJB 也需要對(duì) JNDI 有一個(gè)詳細(xì)的了解
          • 對(duì)容器的依賴使得EJB 2.0只能用于服務(wù)器組件的開(kāi)發(fā),無(wú)法實(shí)現(xiàn)一次編寫,四處運(yùn)行的面向構(gòu)件的開(kāi)發(fā)
          所有這些復(fù)雜度和缺陷,都導(dǎo)致EJB 2.0的采用無(wú)法真正簡(jiǎn)化開(kāi)發(fā)并提高生產(chǎn)力。

          EJB 3.0 旨在解決以往EJB 2.0 模型的復(fù)雜性和提高靈活性,具體體現(xiàn)在:

          • 消除了不必要的接口Remote, Home, EJB以及回調(diào)方法實(shí)現(xiàn)
          • 實(shí)體Bean采用了POJO模型,一個(gè)簡(jiǎn)單的java bean就可以是一個(gè)Entity Bean。無(wú)需依賴容器運(yùn)行和測(cè)試
          • 全面采用O/R Mapping技術(shù)來(lái)實(shí)現(xiàn)數(shù)據(jù)庫(kù)操作
          • 實(shí)體Bean可以運(yùn)用在所有需要持久化的應(yīng)用,不管是客戶端還是服務(wù)器端。從而真正實(shí)現(xiàn)面向構(gòu)件的開(kāi)發(fā)
          • 實(shí)體 bean 現(xiàn)在支持繼承和多態(tài)性
          • 靈活豐富的EJB3查詢語(yǔ)言
          • SQL支持
          • 使用元數(shù)據(jù)批注代替部署描述符,減少?gòu)?fù)雜配置和提高可維護(hù)性
          • 將常規(guī) Java 類用作 EJB 并將常規(guī)業(yè)務(wù)接口用于 EJB

          EJB 3中的元數(shù)據(jù)批注:Annotation

          EJB3 規(guī)范中引入了元數(shù)據(jù)批注(Annotation)。Annotation是從J2SE 1.5開(kāi)始稱為java語(yǔ)言的一部分。Annotation并不是一個(gè)新的事物,在J2SE 1.5以前,人們已經(jīng)自行引入了象著名的XDoclet等外掛式的元數(shù)據(jù)批注方法。而在.NET中,元數(shù)據(jù)批注也早已經(jīng)是C#語(yǔ)言的成分了。

          在以往,我們都是采用xml作為配置批注,但采用文本的xml配置存在一些缺陷:

          • 描述符多,不容易記憶和掌握
          • 無(wú)法做自動(dòng)的校驗(yàn),需要人工排錯(cuò)
          • 當(dāng)系統(tǒng)變大時(shí),大量的xml配置難以管理
          • 讀取和解析xml配置非常耗時(shí),導(dǎo)致應(yīng)用啟動(dòng)緩慢,不利于測(cè)試和維護(hù)
          • 做O/R Mapping的時(shí)候需要在java文件和xml配置文件之間交替,增大了工作量
          • 運(yùn)行中保存xml配置需要消耗額外的內(nèi)存

          采用元數(shù)據(jù)可以很好的解決這些問(wèn)題:

          • 描述符大量減少。以往在xml配置中往往需要描述java屬性的類型,關(guān)系等等。而元數(shù)據(jù)本身就是java語(yǔ)言,從而省略了大量的描述符
          • 編譯期校驗(yàn)。錯(cuò)誤的批注在編譯期間就會(huì)報(bào)錯(cuò)。
          • 元數(shù)據(jù)批注在java代碼中,避免了額外的文件維護(hù)工作
          • 元數(shù)據(jù)被編譯成java bytecode,消耗小的多內(nèi)存,讀取也非常迅速,往往比xml配置解析快幾個(gè)數(shù)據(jù)量級(jí),利于測(cè)試和維護(hù)

          第一個(gè)Entity Bean:HelloWorld

          EJB3中的Entity Bean是如此的簡(jiǎn)單,就是一個(gè)普通的java bean加上一些精煉的元數(shù)據(jù)批注。

                          
          @Entity
          @Table( name="helloTable" )
          public class HelloEntityBean {
          
              private int id;
              private String foo;
          
              /**
               * The entity class must have a no-arg constructor.
               */
              public HelloEntityBean() {
              }
          
              public HelloEntityBean(int id, String foo) {
                  this.id = id;
                  this.foo = foo;
              }
          
              @Id(generate=GeneratorType.NONE)
              public int getId() {
                  return id;
              }
          
              public void setId(int id) {
                  this.id = id;
              }
          
              public String getFoo() {
                  return foo;
              }
          
              public void setFoo(String foo) {
                  this.foo = foo;
              }
          
              public String toString(){
                  return "HelloEntityBean: id=" + id + ", foo=" + foo;
              }
          }
                          
                      

          代碼中元數(shù)據(jù)的說(shuō)明:

          @Entity :EJB3 Entity Bean的批注,表明當(dāng)前的java bean作為一個(gè)Entity Bean來(lái)處理。

          @Table( name="helloTable" ) :顧名思義,定義當(dāng)前Entity對(duì)應(yīng)數(shù)據(jù)庫(kù)中的表。

          @Id(generate=GeneratorType.NONE) :我們把HelloEntityBean的id屬性定義為主鍵。主鍵產(chǎn)生策略為GeneratorType.NONE,意味這是一個(gè)業(yè)務(wù)主鍵。

          就這么簡(jiǎn)單!

          解說(shuō)Entity

          從EJB3.0開(kāi)始,Entity Bean持久化規(guī)范與EJB的其他規(guī)范如Session Bean, Message Driven Bean和EJB3容器規(guī)范開(kāi)始分離,單獨(dú)作為一個(gè)持久化API。而在將來(lái),該持久化API很可能會(huì)從EJB3.0規(guī)范中脫離出來(lái)成為一個(gè)獨(dú)立的規(guī)范Java Persistence API。作為Java平臺(tái)上的通用數(shù)據(jù)訪問(wèn)標(biāo)準(zhǔn)接口。 為了跟規(guī)范一致,我們將在開(kāi)發(fā)手冊(cè)中將Entity Bean稱為Entity。

          雖然EJB3 Entity可以是很簡(jiǎn)單的java bean,只要批注了@Entity或者在xml配置中作了說(shuō)明,就被做一個(gè)可持久化的Entity處理。 但還是需要遵行一定的規(guī)則:

          • Entity類必須要有一個(gè)無(wú)參數(shù)的public或者protected的Constructor。
          • 如果在應(yīng)用中需要將該Entity類分離出來(lái)在分布式環(huán)境中作為參數(shù)傳遞,該Entity Class需要實(shí)現(xiàn)java.io.Serialzable接口。
          • Entity類不可以是final,也不可有final的方法。
          • abstract類和Concrete實(shí)體類都可以作為Entity類。
          • Entity類中的屬性變量不可以是public。Entity類的屬性必須通過(guò)getter/setter或者其他的商業(yè)方法獲得。

          定義對(duì)Entity中屬性變量的訪問(wèn)

          在絕大部分的商業(yè)應(yīng)用,開(kāi)發(fā)人員都可以忽略這部分無(wú)需關(guān)心。但如果你需要編寫復(fù)雜的Entity類的話,你需要了解這個(gè)部分。復(fù)雜的Entity類是指在Entity類的getter/setter和商業(yè)方法中包含比較復(fù)雜的業(yè)務(wù)邏輯而不是僅僅返回/符值某個(gè)屬性。

          在大部分的情況下,我們都建議使Entity類中setter/getter中的邏輯盡可能簡(jiǎn)單,除了必要的校驗(yàn)符值外,不要包含復(fù)雜的業(yè)務(wù)邏輯,例如對(duì)關(guān)聯(lián)的其他Entity類進(jìn)行操作。但有些情況下,我們還是需要在Entity類的setter/getter方法中包含商業(yè)邏輯。這時(shí)候,采用何種屬性訪問(wèn)方式就可能會(huì)影響代碼的性能甚至是邏輯正確產(chǎn)生影響。

          EJB3持久化規(guī)范中,在默認(rèn)情況下所有的屬性都會(huì)自動(dòng)的被持久化,除非屬性變量用@Transient元數(shù)據(jù)進(jìn)行了標(biāo)注。針對(duì)可持久化屬性定義了兩種屬性訪問(wèn)方式(access): FIELD和PROPERTY。

          • 如果采用access=FIELD, EJB3 Persistence運(yùn)行環(huán)境(EJB3持久化產(chǎn)品,如Liberator EJB3)直接訪問(wèn)對(duì)象的屬性變量,而不是通過(guò)getter。這種訪問(wèn)方式也不要求每個(gè)屬性必須有g(shù)etter/setter。如果需要在getter中包含商業(yè)邏輯,應(yīng)該采用access=FIELD的方式。
          • 如果采用access=PROPERTY, EJB3 Persistence運(yùn)行環(huán)境將通過(guò)Entity類上的getter來(lái)訪問(wèn)對(duì)象的屬性變量,這就要求每個(gè)屬性變量要有g(shù)etter/setter方法。在EJB3中,默認(rèn)的屬性訪問(wèn)方式是PROPERTY。access=PROPERTY時(shí)getter/setter的邏輯應(yīng)該盡量簡(jiǎn)單。

          規(guī)范中access方式還有多一層含義。就是采用access=FIELD時(shí),元數(shù)據(jù)應(yīng)該批注在屬性上。

                          
              @Id(generate=GeneratorType.NONE)
              private int id;
              private String foo;
          
              /**
               * The entity class must have a no-arg constructor.
               */
              public HelloEntityBean() {
              }
          
              
              public int getId() {
                  return id;
              } 
                      

          采用access=PROPERTY(默認(rèn)方式)時(shí),元數(shù)據(jù)應(yīng)該批注在對(duì)應(yīng)屬性變量的getter上。

                               
              private int id;
              private String foo;
          
              /**
               * The entity class must have a no-arg constructor.
               */
              public HelloEntityBean() {
              }
          
              @Id(generate=GeneratorType.NONE)
              public int getId() {
                  return id;
              } 
                           

          為了方便開(kāi)發(fā),Liberator EJB3實(shí)現(xiàn)對(duì)元數(shù)據(jù)批注的位置比規(guī)范規(guī)定的寬松,針對(duì)屬性變量或它的getter進(jìn)行批注都可以,不受access類型的影響。

          對(duì)Entity類中,getter/setter的命名規(guī)則遵從java bean規(guī)范。

          Entity類中的屬性變量可以是以下數(shù)據(jù)類型:

          • 原始數(shù)據(jù)類型和他們的對(duì)象類型
          • java.lang.String
          • java.math.BigInteger
          • java.math.BigDecimal
          • java.util.Date
          • java.util.Calendar
          • java.sql.Date
          • java.sql.Time
          • java.sql.Timestamp
          • byte[]
          • Byte[]
          • char[]
          • Character[]
          • enums
          • Entity類
          • 嵌入實(shí)體類(embeddable classes)

          還可以是以下集合類型:

          • java.util.Collection和它的實(shí)體類
          • java.util.Set和它的實(shí)體類
          • java.util.List和它的實(shí)體類
          • java.util.Map和它的實(shí)體類

          主鍵和實(shí)體標(biāo)識(shí)(Primary Key and Entity Identity)

          每個(gè)Entity類都必須有一個(gè)主鍵。在EJB3中定義了兩種主鍵:

          • 鍵單主鍵
          • 復(fù)合主鍵

          簡(jiǎn)單主鍵必須對(duì)應(yīng)Entity中的一個(gè)屬性變量(Instance Variable),而該屬性對(duì)應(yīng)數(shù)據(jù)庫(kù)表中的一列。使用簡(jiǎn)單主鍵,我們只需要用@Id元數(shù)據(jù)對(duì)一個(gè)屬性變量或者她的getter方法進(jìn)行批注。

          當(dāng)我們需要使用一個(gè)或多個(gè)屬性變量(表中的一列或多列)聯(lián)合起來(lái)作為主鍵,我們需要使用復(fù)合主鍵。復(fù)合主鍵要求我們編寫一個(gè)復(fù)合主鍵類( Composite Primary Key Class )。復(fù)合主鍵類需要符合以下一些要求:

          • 復(fù)合主鍵類必須是public和具備一個(gè)沒(méi)有參數(shù)的constructor
          • 復(fù)合主鍵類的每個(gè)屬性變量必須有g(shù)etter/setter,如果沒(méi)有,每個(gè)屬性變量則必須是public或者protected
          • 復(fù)合主鍵類必須實(shí)現(xiàn)java.io.serializable
          • 復(fù)合主鍵類必須實(shí)現(xiàn)equals()和hashcode()方法
          • 復(fù)合主鍵類中的主鍵屬性變量的名字必須和對(duì)應(yīng)的Entity中主鍵屬性變量的名字相同
          • 一旦主鍵值設(shè)定后,不要修改主鍵屬性變量的值
          一起看一個(gè)復(fù)合主鍵的例子。Entity類Person,它的主鍵屬性變量是firstName和lastName。
                          
              @Id
              private String firstName;
              
              @Id
              private String lastName;
          
              public Person() {
              }
             
              
              
                      
          Person的復(fù)合主鍵類:
                          
          public class PersonPK implements java.io.Serializable{
              
              private String firstName;
              private String lastName;
          
              public PersonPK() {
              }
          
              public String getFirstName() {
                  return firstName;
              }
          
              public void setFirstName(String firstName) {
                  this.firstName = firstName;
              }
          
              public String getLastName() {
                  return lastName;
              }
          
              public void setLastName(String lastName) {
                  this.lastName = lastName;
              }
          
              public boolean equals(Object o) {
                  if (this == o) return true;
                  if (!(o instanceof PersonPK)) return false;
          
                  final PersonPK personPK = (PersonPK) o;
          
                  if (!firstName.equals(personPK.firstName)) return false;
                  if (!lastName.equals(personPK.lastName)) return false;
          
                  return true;
              }
          
              public int hashCode() {
                  int result;
                  result = firstName.hashCode();
                  result = 29 * result + lastName.hashCode();
                  return result;
              }
          }                
                          

          posted on 2006-07-03 00:57 liaojiyong 閱讀(1143) 評(píng)論(0)  編輯  收藏 所屬分類: EJB

          主站蜘蛛池模板: 盐城市| 巴楚县| 同德县| 襄汾县| 巩留县| 绵阳市| 自贡市| 唐海县| 宁都县| 遵义县| 白朗县| 房产| 多伦县| 岳阳市| 桐梓县| 贡觉县| 都江堰市| 通道| 剑阁县| 廉江市| 吉安市| 盘锦市| 论坛| 成都市| 许昌市| 凤台县| 乌什县| 安西县| 永州市| 沭阳县| 隆子县| 德州市| 竹北市| 武汉市| 加查县| 宁城县| 盱眙县| 竹山县| 乐山市| 天柱县| 镇康县|