使用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关联,并有着它自己的数据库设置。它会自地捆到服器的事管理器中

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值