使用EJB 3.0簡化Java開發

  Java業級版本,或者Java EE(以前叫J2EE),開發器端的用來是一個大的但卻又複雜的的平臺。從它生之日起,複雜一直是使用Java EE猶豫不決的一個重要因素。在JavaWorld的以前的一篇文章化之路中,我指出了那些Java EE變複雜的因素,其中很多都是與當前的EJB 2.1範有

  在去的三年中,Java放源代社區,Java社區(JCP)以及主要的Java EE商,一直致力於Java EE簡單例來:新的設計範例,比如POJO,服務攔截器和依注入,可以在實際應用中用來Java EE開發了。有,新的工具和框架,比如Hibernate, AOP(aspect-oriented programming,面向方面)Struts,XdocletSpring, 也已被廣泛用於同一目的。

  化不是功能的減少

  化一個程模型並沒有減少它的功能。化只是把複雜邏輯隱藏到了框架代或可重用的件中去了。根本上,它是把複雜西從需要開發者直接管理的地方移到了大多數開發者看不到的地方。

  上述的模板和工具初學者更容易上手,同也提高了有經驗Java開發者的生力,在它正在被JCP合併到下一代的Java EE準中(比如:EJB 3.0)。由Java開發Raghu Kodali最近所做的研究:Java EE的示例程序RosterAppEJB 2.1EJB 3.0可以減少百分之五十以上的代

  JavaEJB3.0背後的關鍵,它將POJOPOJO持久化和依注入一起一個完整的企業級件解決方案。篇文章中,我使用了一個示例:JBoss EJB 3.0 TrailBlazer,來演示使用注釋開發輕EJB 3.0 POJO用。TrailBlazer用使用EJB 3.0中不同的工具和API復實現了一個投資計算器。示例程序完全可以在JBoss 用服4.0.3版本中運行,並且與最新的EJB 3.0準完全兼容(完成)

  始體一下注釋驅動編程模型的好吧。

  EJB 3.0的注釋驅動編程模型

  從開發者的點來看,EJB 3.0廣泛地使用了Java .有兩個關鍵優勢:取代了多的XML配置文件並且消除了件模型需求。

   vs XML

  基於XML的佈署描述和注一起都可以用來在Java EE用中配置服的相屬性。它的區在於:XML文檔是與代開處理的,特是在運行刻,而注是與代碼編譯在一起的並被編譯檢查的。開發者來說這就有了一些重要的含,正如我下面所列出的:

  冗:XML配置文件是出了名的冗的。了配置代XML文件必須復多信息:比如代名字和方法名字。Java釋則不同,它是代的一部分,不需要外的引用就可以指明配置信息。

  壯性:XML文件中重的代信息引入了多的可能。比如,如果你寫了方法的名字,那用直到運行刻纔會出錯垮掉。也就是XML配置文件的壯性就不如注,注是被編譯檢查的,並和其它代一起被理的。

  靈活性:既然XML文件是在代之外被理的,那也就是基於XML的配置信息不是編碼的,是可以以後修改的。部署的靈活性管理是非常非常重要的特性。

  注簡單易用的,已大多數用來了。XML文件更複雜,但能被用來理更高問題EJB 3.0你通來配置大多數的用。EJB 3.0也支持用XML文件來覆蓋默的注,及配置像數據庫聯這樣的外部源。

  除了替XML描述符,注也允們廢除困EJB 1.x, EJB 2.x件模型。

  POJO vs

  EJB 件是容器管理(container-managed)象。容器在運行刻操作Bean的狀和行爲發生,EJB 2.1範定了一個Bean遵守的格的件模型。一個EJB從某一抽象承,並容器提供了回調子。既然Java只支持單繼承,件模型就限制了開發者使用EJB建一個複雜對構的能力。當把複雜用數據映射到 Bean中的候,正如我第二部分中看到的,會成一個很大的問題

  在EJB 3.0中,所有的容器服都可以通使用注POJO用來配置和交付。大多數情況下,並不需要特殊的JBoss EJB 3.0 TrailBlazer示例看一下如何在EJB 3.0中使用注

 開發藕合鬆散的服務對

  像Java EE這樣的企業級件的一個最重要的好是允許開發者使用藕合鬆散的件來開發應用。僅僅自己布的商接口來藕合。因此件的實現類可以在不改變應用其餘部分的情況下改自己的實現將會使用更加壯,更容易測試,更易移植。EJB 3.0使得在POJO建藕合鬆散的商業組得更簡單了。

  Session bean

  在EJB 3.0用中,藕合鬆散的服務組件的典型用是Session Bean。一個Session Bean至少有一個接口(也就是:接口),其它件通得服。下面的代碼爲的投資計算器服提供了商接口。它只有一個方法,根據定的起始年止年,增率,月存金算出資額

public interface Calculator {
  public double calculate (int start, int end,
                double growthrate, double saving);
}

  Session bean類簡單實現了商接口。你必使用StatelessStateful來告EJB 3.0容器POJO是一個Session Bean。有狀(Stateful)session bean在不同的服務請間維護着客的狀。相反地,於無狀(Stateless)session bean次的求都是被隨機挑session bean理的。些行是與EJB 2.1中的有狀和無狀session bean的定是一致的。EJB 3.0容器算出何時實例化Bean象,並通接口其可用。下面是session bean實現類的代:

@Stateless
public class CalculatorBean implements Calculator {
  public double calculate (int start, int end,
                    double growthrate, double saving) {
    double tmp = Math.pow(1. + growthrate / 12.,
                          12. * (end - start) + 1);
    return saving * 12. * (tmp - 1) / growthrate;
  }
}

  你也可以一個session bean指明多個接口-一個本地客,一個爲遠程客。只要使用@Local@Remote來區分。下面的代片斷示了同時實現了本地和程接口的CalculatorBean。如果你沒有@Local@Remotesession bean接口默認爲本地接口。

@Stateless
@Local ({Calculator.class})
@Remote ({RemoteCalculator.class})
public class CalculatorBean implements Calculator, RemoteCalculator {

  public double calculate (int start, int end,
                           double growthrate, double saving) {
    double tmp = Math.pow(1. + growthrate / 12., 12. * (end - start) + 1);
    return saving * 12. * (tmp - 1) / growthrate;
  }

  public String getServerInfo () {
    return "This is the JBoss EJB 3.0 TrailBlazer";
  }
}

  Session beanJNDI得到bean的一個存根(Stub)象。容器所提供的存根實現session bean的商接口。所有針對存根的調用都被引向了容器,由容器調用相實現類中的接口。於有狀的的session bean,你必自己在客存存根象,這樣次的後續調,容器才知道要提供相同的的bean例。下面的片斷示如何調session bean.在後面,你將會學到取存根象的更簡單的方法。

InitialContext ctx = new InitialContext();
cal = (Calculator) ctx.lookup(Calculator.class.getName());

double res = cal.calculate(start, end, growthrate, saving);

Session bean生命週期的管理

  達到藕合鬆散的目的,用把session bean例的建、存、銷燬全部交EJB 3.0容器(也就是,反向控制設計模式)用只和bean的商接口打交道。

  但如果用需要session象更好的控制呢?比如用可能需要在session bean候初始化數據庫聯接,而在銷燬bean時關閉外部的接。上述些,你都可能通bean中定生命週期的回調方法來實現些方法將會被容器在生命週期的不同調(:建或銷燬時)。通使有下面所列的注EJB 3.0你將任何方法指定調方法。不同於EJB 2.1EJB 2.1中,所有的回調方法必須實現,即使是空的。EJB 3.0中,bean可以有任意數量,任意名字的回調方法。

  @PostConstruct:bean象完成例化後,使用了個注的方法會被立即調用。個注適用於有狀和無狀session bean

  @PreDestroy:使用個注的方法會在容器從它的象池中銷燬一個無用的或者期的bean調用。同適用於有狀和無狀session bean.

  @PrePassivate:當一個有狀session bean例空閒過長時間,容器將會化它,並把它的狀保存下來。使用個注的方法會在容器bean例之前調用。適用於有狀session bean

  @PostActivate:當客端再次使用已化的的有狀session bean,新的例被建,狀被恢。使用此注session bean會在bean的激活完成時調用。

  @Init:個注指定了有狀session bean初始化的方法。它區@PostConstruct在於:多個@Init方法可以同存在於有狀session bean 中,但bean例只會有一個@Init的方法會被調用。取決於bean是如何建的(細節請EJB 3.0)@PostConstruct@Init之後被調用。

  另一個有用的生命週期方法注@Remove,特於有狀session bean。當用通存根調用使用了@Remove的方法,容器就知道在方法行完後,要把bean例從池中移走。

@Stateful
public class CalculatorBean implements Calculator, Serializable {

    // ... ...
   
    @PostConstruct
    public void initialize () {
        // Initializes the history records and load
        // necessary data from database etc.
//
初始化記錄,並從數據中裝入必需的數據。
    } 
   
    @PreDestroy
    public void exit () {
        // Save history records into database if necessary.
//
如有必要記錄保存至數據
    }  
   
    @Remove
    public void stopSession () {
        // Call to this method signals the container
        // to remove this bean instance and terminates
        // the session. The method body can be empty.
//
調個方法來通知容器將bean例移除並中止session.
//
個方法可以空。
    }
   
    // ... ...
}

消息驅動bean

  Session bean提供了同步調用的方法。另一個重要的藕合鬆散服務類型是一過進入的消息來觸的異(比如:emailJava消息服務產生的消息)EJB 3.0的消息驅動bean(MDB)設計用來專門處理基於消息求的件。

  一個MDB須實現MessageListener接口。當容器檢測bean守候的列一條消息,就調onMessage()方法,將消息作參數入。MDBOnMessage()中決定如何消息。你可以用注來配置MDB聽哪一條列。當MDB部署,容器將會用到其中的注信息。在下面的例子中,CalculatorBean MDB會在JMSqueue/mdb有消息時調用。MDB解析消息,並根據消息內容算投

@MessageDriven(activateConfig =
{
  @ActivationConfigProperty(propertyName="destinationType",
    propertyValue="javax.jms.Queue"),
  @ActivationConfigProperty(propertyName="destination",
    propertyValue="queue/mdb")
})
public class CalculatorBean implements MessageListener {

  public void onMessage (Message msg) {
    try {
      TextMessage tmsg = (TextMessage) msg;
      Timestamp sent =
          new Timestamp(tmsg.getLongProperty("sent"));
      StringTokenizer st =
          new StringTokenizer(tmsg.getText(), ",");

      int start = Integer.parseInt(st.nextToken());
      int end = Integer.parseInt(st.nextToken());
      double growthrate = Double.parseDouble(st.nextToken());
      double saving = Double.parseDouble(st.nextToken());

      double result =
          calculate (start, end, growthrate, saving);
      RecordManager.addRecord (sent, result);

    } catch (Exception e) {
      e.printStackTrace ();
    }
  }

  // ... ...
}

  注入

  在上一中,你學到了如何開發藕合鬆散的服務組件。但是,了存取那些服務對象,你需要通器的JNDI找存根(session bean)或消息(MDB)JNDI找是把客端與實際實現解藕的關鍵步驟。但是,直接使用一個字符串來JNDI找並不雅。有這樣幾個原因:

  客端與服端必有一致的基於字符串的名字。它沒有在編譯時得到認證或在佈署得到檢查

  從JNDI返回的服務對象的型沒有在編譯時進檢查,有可能在運行現轉換(casting)錯誤

  冗找代,有着自己的try-catch碼塊,在用之是重的和

 EJB 3.0任何POJO,提供了一個簡單的和雅的方法來解藕服務對象和源。使用@EJB,你可以將EJB存根象注入到任何EJB 3.0容器管理的POJO中。如果注用在一個屬性量上,容器將會在它被第一次訪問之前賦值給它正確的。下面的例了演示了怎CalculatorBean無狀session bean的存根注入到CalculatorMDB MDB中。

public class CalculatorMDB implements MessageListener {

  @EJB Calculator cal;
 
  // Use the cal variable
  // ... ...
}

  注如果被用在JavaBean格的setter方法上,容器會在屬性第一次使用之前,自地用正確的參數調beansetter方法。下面的片斷演示了是如何做的:

public class CalculatorMDB implements MessageListener {

  Calculator cal;
 
  @EJB
  public void setCal (Calculator cal) {
    this.cal = cal;
  }
 
  // Use the cal variable
//
使用cal
  // ... ...
}

  除@EJB之外,EJB 3.0也支持@Resource來注入來自JNDI的任何源。下面的例子中,我演示瞭如何注入服器端默入的TimerServiceSessionContext象,也演示瞭如何注入來自JNDI的命名數據JMS源。

@Resource
TimerService tms;

@Resource
SessionContext ctx;

@Resource (name="DefaultDS")
DataSource myDb;

@Resource (name="ConnectionFactory")
QueueConnectionFactory factory;

@Resource (name="queue/A")
Queue queue;

  此外,你也可以把一個容器管理的持久化管理器(也就是,EntityManager-似於Hibernate session)注入到EJB 3.0 POJO中。

  把容器服POJO

  除了管理生命週期和訪問藕合鬆散的服務對象外,EJB 3.0過簡單的注POJO提供了運行刻服

  

  最有用的容器服可能就是事管理服,當用出或異常,它保了數據的完整性。你可以簡單地將一個POJO方法申明它的事屬性。這樣容器就可以在合適的上下文中運行個方法。例來,下面的代申明瞭容器在運行updateExchangeRate()須創建一個新的事。當個方法退出提交事實際上,所有在updateExchangeRate()中被調用的方法都在此事中運行,除非有特申明。在updateExchangeRate()中的數據操作要全部成功,要全部失

@Stateless
public class CalculatorBean implements Calculator {

  // ... ...

  @TransactionAttribute(TransactionAttributeType.REQUIRED)
  public void updateExchangeRate (double newrate) throws Exception {
    // Update the database in a loop.
//
在循中更新數據
    // ... ...
    // The operations in the loop must all be successful or
    // the database is not updated at all.
//
中的操作必全部成功或者根本不更新。
  }
}

安全

  容器也提供了安全服行用戶認證和根據用戶規則來限制POJO訪問對每一個POJO,你可以通使用@SecurityDomain釋爲它指定一個安全域, 安全域告容器到哪裏去找密和用角色列表。JBoss中的other域表明文件是classpath中的users.propertesroles.properties這樣對每一個方法來,我可以使用一個安全限制注來指定可以運行個方法。比如,下面的例子,容器所有試圖調addFund()的用戶進認證,只允許擁AdminUser角色的用戶實際運行它。如果你沒有登或者沒有以管的身份登,一個安全意外將會拋出。

@Stateless
@SecurityDomain("other")
public class CalculatorBean implements Calculator {

  @RolesAllowed({"AdminUser"})
  public void addFund (String name, double growthrate) {
    // ... ...
  }

  @RolesAllowed({"AdminUser"})
  public void addInvestor (String name, int start, int end) {
    // ... ...
  }

  @PermitAll
  public Collection <Fund> getFunds () {
    // ... ...
  }
 
  // ... ...

  @RolesAllowed({"RegularUser"})
  public double calculate (int fundId, int investorId,
                                       double saving) {
    // ... ...
  }
}

  通用截器

  事和安全服都可以被看作是容器管理的運行截器。容器截了EJB存根的調用,並在其上用事上下文或行安全限制。

  在EJB 3.0中,你可以自己寫截器來展容器服。使用@AroundInvoke,你可以將任意bean方法作爲攔截器方法在任意bean方法之前和之後運行。下面的例子中,log()方法是一個截器,它算和記錄了其它bean方法的時間:

@Stateful
public class CalculatorBean implements Calculator {

  // Bean methods that are to be intercepted by "log()"
  // bean
方法將被log()方法
//
  // ... ...
 
  @AroundInvoke
  public Object log (InvocationContext ctx)
                            throws Exception {

    String className = ctx.getBean().getClass().getName();
    String methodName = ctx.getMethod().getName();
    String target = className + "." + methodName + "()";

    long start = System.currentTimeMillis();
    System.out.println ("Invoking " + target);
    try {
      return ctx.proceed();
    } catch(Exception e) {
      throw e;
    } finally {
      System.out.println("Exiting " + target);

      cal.setTrace(cal.getTrace() + "
" +
                   "Exiting " + target);
      long time = System.currentTimeMillis() - start;
      System.out.println("This method takes " +
                          time + "ms to execute");
    }
  }
}

 下一?

  在第一部分中,我大致地討論EJB 3.0基於POJO程模型和如何在EJB 3.0開發藕合鬆散的服務組件。在第二部分中,我會討論EJB 3.0的另一個主要的概念:可管理的POJO持久性。


 

使用EJB 3.0Java開發       

 

 第一部分中,我討論了在企業級JavaBean 3.0(EJB)中注釋驅動POJO程模型。我述瞭如何開發POJO,如何容器服使用POJO, 如何使用依注入來用。POJO主要是用來封裝用的商業邏輯。在商業邏輯的背後,今的大多數用都有由一個高性能的系型數據支撐的數據模型

      第二部分中,我將討論EJB 3.0bean如何利用POJO和注優勢來極大地化你的數據模型以及它與後臺係數據的持久化。在我們進EJB 3.0bean細節之前,先來看一下麼對於企業級Java用,數據模型和持久化是如此巨大的一個挑

      -系映射(ORM

      Java中,所有的數據都被模型化並且封裝在了象的樹結構中。但是在後端的系型數據中,數據被模型化爲關系型表,它共享的域()相互關聯起來。相同的數據卻有兩個視圖這對業級Java開發者來是一個艱難的挑:當你想從持久化的數據存中存取數據,你必象與系表達之來回轉換程叫做象-系映射(ORM)。在Java EE(Java版,以前叫做J2EE),你可以通兩個途徑來實現對象-系映射。

      的:你可以使用Java數據庫連接來直接操作持久化-簡單應用的直截了當的解決方案。JDBC API緊貼系型數據表、行和列之後的數據模型。你必地在用的內部象模型與JDBC象模型之間進轉換,如果你的用的內部模型本身就似於2系表的,那採用JDBC是最佳手段。

      :你可以把ORM框架。框架通常向你提供一個可以和任意數據行交互的API。通那個API,你可以存取和查詢數據。框架在後臺完成了框架象的轉換。因特定的系型SQL查詢不適合象接口,ORM框架通常定它自己的查詢語言,並且自動爲當前系型數據生成正確的SQL句。複雜的數據模型的用來,基於框架的手段能省很多時間並降低了出的可能。

      象數據

      一個象型數據直接在數據中存取和象。因不再需要ORM,所以它Java用非常適合。不幸的是,今的象型數據系型數據說還不成熟,速度也慢。你可以這樣說,一個好的ORM框架從根本上來,就是爲關系型數據提供一個象型數據的接口。兩者它都要做到最好。

      篇文章,我將重點放在專爲業級Java ORM設計的自框架上。下一,我將提到幾個流行的ORM框架和EJB 3.0中幾個關鍵的革新。

      ORM 框架

      EJB beanJava EE官方ORM解決方案。但是,在EJB1.x2.x中,bean以使用是出了名的,原因如下:

      ●EJB 1.x2.xbean遵守一種嚴格的件模型。一個bean須實現一個home接口和一個商接口。它從某抽象承,而且必須實現其所有方法,即使它多數空。這樣的一種嚴件模型使得想從EJB 1.x2.xbean中構建面向象的數據模型幾乎得不可能了。
      ●EJB 1.x
2.x容器需要特xml配置文件來建立bean系型數據中的表映射。那些文件是非常單調乏味和容易出的。

      而言之,EJB 1.x2.xbean是一個設計拙劣的ORM框架。它既沒有滿Java數據象模型的需求,也沒有滿系表數據模型的需求。出於EJB 1.x2.xbean的不滿開發找其它的ORM方案。實際使用中,源的Hibernate(JBoss開發)Oracle公司的TopLink是最成功的兩個POJO ORM框架。HibernateTopLink都是基於POJO的。它不依於任何件模型。作替代,它使用POJO數據(簡單JavaBean式的),自地解出如何映射它,以及它系(系型數據)。通常,JavaBean映射到一數據表,並根據數據表中的外映射出系。你可以在一個簡單直接的xml配置文件中指明ORM的配置信息,比如JavaBean類對應的表名和屬性對應的列名。你可以通框架中的工具(如:Hibernate中的Session)來那些POJO行操作(如:存取和)

      EJB 3.0是建立在HibernateTopLink的思想和成功之上。它Java EE提供了一個準的POJO ORM框架。另外,EJB 3.0有兩個超越今所有持久化解決方案的關鍵革新:

      ●沒有使用XML文件來指明ORM配置信息, EJB 3.0許開發者直接在POJO中注出映射信息。例來,你可以用注來指明JavaBean屬性對應系型表列。在篇文章的後面,你將看到更多的例子。注使得映射更直接,更容易維護了。
      ●EJB 3.0
爲實bean了一個新的檔格式。個檔案使用一獨立的,後端數據ORM用的配置集來定一個持久化上下文。在篇文章的後面,我會討論持久化上下文。

      在,幾個簡單的例子來看一下EJB 3.0是如何完成POJO ORM的。

映射一個簡單

      EJB 3.0中,bean都是一個簡單JavaBean式的了告EJB 3.0容器類應該爲持久化行映射,你應該@Entity來注釋這

      一個bean映射到一個系型數表。默地,表名對應類名。你可以用@Table爲類指定另一個表。一個JavaBean屬性映射到表的列上,同的,默列名就是屬性名。你可以用@Column在屬性的Setter方法上來改變這種認關系。下面是一個EJB 3.0簡單例子:

@Entity
// @Table (name="AlternativeTableName")
public class Person implements Serializable {
 
  protected int id;
  protected String name;
  protected Date dateOfBirth;
 
  public void setId (int id) {
    this.id = id;
  }
 
  @Id(generate = GeneratorType.AUTO)
  public int getId () {
    return id;
  }
 
  public void setName (String name) {
    this.name = name;
  }
 
  // @Column (name="AlternativeColumnName")
  public String getName () {
    return name;
  }
 
  public void setDateOfBirth (Date dateOfBirth) {
    this.dateOfBirth = dateOfBirth;
  }
 
  public Date getDateOfBirth () {
    return dateOfBirth;
  }
}

      當容器把Person映射到Person SQL數據表以後,一個Person例就是表中的一條數據記錄

      映射一個簡單JavaBean是容易的。但自ORM框架真正光之在於映射互相關聯象。下一中,我看一下EJB 3.0如何操作系。

     

      在一個數據模型裏面,一般來說類相互之都會有某種聯系。比如,一個Person(個人)象可以和一個Resume()象相關聯,反來也一(一系);一個Person象可以和多個CreditCard(信用卡)象相,而一個CreditCard象只能和一個Person象相(一系)。多個Person象可以和一個Address(地址)象相,而一個Person象只能對應一個Address象(多系)。(者注:此原著筆, PersonAddress位置倒了;者注:我看兩者是多多的系。一家人住在同一個地方,個地址一家人來是一多的系;房主在的地方又了一套房,房主與地址的系是一多的系。)

在一個數據模型中,象指用來操作那些系。,一個Person象可以有一個屬性(也就是域)指向一個Resume象。而另一個屬性是CreditCard象的集合。了告知EJB 3.0容器系,你只需簡單地在POJO中注JavaBean屬性。

@Entity
public class Person implements Serializable {

  // ... ...
  protected Resume resume;
  protected CreditCard [] cards;
  protected Address addr;
 
  // ... ...
   
  @OneToOne
  public Resume getResume () {
    return resume;
  }
 
  // ... ...
 
  @ManyToOne
  // @JoinColumn (name="MyCustomId")
  public Address getAddr () {
    return addr;
  }
 
  // ... ...
 
  @OneToMany
  public Collection <CreditCard> getCards () {
    return cards;
  }
}

      系型數據中,那些系自地被EJB 3.0容器使用外來重建了。例來Person表有一個外包含了Resume表中相的主。運行EJB 3.0容器加了一一的系:它保Resume鍵值對Person表中的一行是唯一的。了啓用Resume表到Person表的雙向查詢,你可以Resume表中定一個Person屬性,並把它也加上@OneToOne

      Person表中也有一個外包含了Address表中相行的主這種情況下,相同的Address可以出在多個Person行中,是多系。於一多的系,映射稍有一點複雜,因列是定在多一表中的。於是,在CreditCard中,你必@ManyToOne來定一個Person屬性。
外部字段名

      ORM中使用的外部字段的名字是由容器自決定的或者由@JoinColumn式的指定。

      上面討論系只是bean間關系的一種類型,另外一重要系是承。

     

      面向設計方法的一個關鍵概念是承。使用承,你可以建一個複雜而不需要重的代例來Consultant(顧問)是提供有的一個人,那在我的數據模型中,Consultant就從Person(個人)承,並增加了一個價格屬性。不幸的是,當今的系型數據並不存在承的概念。ORM框架主要通以下兩個手段來模仿這種

      ●框架可以爲每一個生成一個獨的表。子的表重了那些從父的字段。子和父儲爲各自對應的表。
      ●
框架可以使用包含了所有子屬性的表。兩種類(和子)例都存於同一中不存在的字段(也就是,子的字段)null了使承映射更爲強壯,表也可以有一個列,它存標記表明行數據映射到哪一個

EJB 3.0bean支持上述兩映射策略,默表映射策略。你可以簡單地用注指明子承策略和區字段的名字。下面是Consultant的例子,它從Person承:

@Entity
@Inheritance(discriminatorValue="C")
@DiscriminatorColumn(name="person_type")
public class Consultant extends Person {

  protected double rate;
 
  public void setRate (double rate) {
    this.rate = rate;
  }
 
  public double getRate () {
    return rate;
  }
}

      從上面的例子中,容器使用默策略將Consultant映射到Person類對應的同一表中。如果表中的person_type字段的值爲C,那一行數據就代表了一個顧問類。否,當前行代表的是一個普通的Person

      持久化檔案

      在你的數據模型有了使用了注EJB 3.0bean,你可以將它在一起佈署到服境中。EJB 3.0爲實bean了一特殊的檔格式,叫做持久化檔案(文件後.par)

      一個.par文件是一組實bean文件加上一個簡單的配置文件META-INF/persistence.xmljar打包文件。persistence.xml文件定了持久化上下文,它告知EJB 3.0哪一個後端數據(數據源)組實bean對應persistence.xml也包含了配置屬性的細節例來JBoss EJB 3.0是在Hibernate 3.0之上實現的,於是你可以通persistence.xml傳遞任意的Hibernate配置選項有一個範例persistence.xml文件,它包含了JBossHibernate用的配置屬性,包括SQL 方言(dialect)和二級緩存。

<entity-manager>
  <name>cal</name>
  <jta-data-source>java:/DefaultDS</jta-data-source>
  <properties>
    <property name="hibernate.dialect" 
            value="org.hibernate.dialect.MySQLDialect" />
    <property name="hibernate.cache.provider_class"
            value="org.jboss.ejb3.entity.TreeCacheProviderHook"/>
    <property name="hibernate.treecache.mbean.object_name"
            value="jboss.cache:service=EJB3EntityTreeCache"/>
  </properties>
</entity-manager>

      體管理器

      一旦你部署了bean, 你必EJB 3.0體管理器的API訪問和操作它EJB 3.0容器爲每個部署的持久化上下文(也就是,.par文件)提供了一個體管理器象。從一個EJB 3.0 session bean POJO(參看第一部分) ,你可以通@PersistenceContext體管理器象注入,並入上下文的名字。

@Stateless
public class ManagerBean implements Manager {

  @PersistenceContext (unitName="cal")
  protected EntityManager em;
 
  // Use "em"
//
使用“em”
  // ... ...
}

基本操作

      建一個數據象並把它存入數據中,你只需簡單地使用Javanew關鍵字來POJO,並把它傳給EntityManager.persist()方法。

Person p = new Person ();
p.setName ("A new baby");
p.setDateOfBirth (new Date ());
em.persist (p);

      要從數據中取得象,你可以使用EJB 3.0查詢語言來搜索數據。下面的例子演示瞭如何將Person表中的所有行作Person Java象的集合來返回。
//
得到所有人的

Collection <Person> persons = (Collection <Person>)
    em.createQuery("from Person p").getResultList();

      可管理的POJO

      過實體管理器保存和取的象是被管理在持久化上下文中的。意味着如果象後來被改了,那這種將會被自動檢測並持久化到數據中。在下面的例子中,我更新了一個可管理的POJO的一個屬性。個改會被EJB 3.0 器自動檢測到並了數據。

Person p = em.find(Person.class, personId);
p.setName ("Another Name");

//p會在當前事務結被自地更新到數據中去。
//
並沒用更多的API調

      既然EJB 3.0只是POJO,就可以能被序列化並通絡傳遞。如果一個象不是被容器建的(也就是,它是從網絡連接中傳遞過來的或者是某一個調用返回的),那持久化上下文並不會管理它。不,你可以通過調EntityManager.merge()方法將一個非管理的POJO合併到持久化上下文中。下面是將一個解序列化的POJO合併入當前持久化上下文中的例子。

InputStream in;
//
初始化入流
Person p = Util.deserialize (in);

// ... ...
em.merge (p);

// p在是一個可管理的象了。p的任何改將會被自動檢測並持久化
p.setName ("Another Name");

      數據

      體管理器象在一個session bean中使用,它是和服器的事上下文定的。體管理器在服器的事提交提交併且同它的內容。在一個session bean中,服器的事地會在調用堆的最後提交。當然,你也可以通爲每個商方法指定具體的事屬性。下面的例子展示瞭如何一個session bean的方法聲明一個新的事

@TransactionAttribute(TransactionAttributeType.REQUIRESNEW)
public void update () {

// 個方法更新Person
//
更新將會在個方法的末尾被提交和刷新到數據

      理中刷新數據操作

      了只在當事提交纔將改更新到數據中,容器將所有數據操作集中到一個批理中,這樣就減少了代價昂的與數據的交互。

      如果你需要在事提交之前將更新刷新到數據中,你可以直接地調EntityManager.flush()方法。或者你可以將一個方法注釋爲@FlushMode(FlushModeType.NEVER),於是事管理器將不會在方法的(也就是事)刷新更新到數據中。這種情況下,你可以手工地來刷新數據數據操作的最大控制。

      總結

      EJB 3.0 提供了一種簡單有效的框架將Java POJO映射到SQL數據中的系型表中。它基於Java中的名字和行智能的默映射策略。但你也可以用一組簡單的注所有的默認值,來複雜系。

      EJB 3.0體管理器提供了簡單API來持久化和從數據象。一個體管理器象與一映射的POJO關聯,並有着它自己的數據庫設置。它會自地捆到服器的事管理器中

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章