第7课
JDBCTM 技术 和 Bean-Managed Persistence

[<<返回] [目录]

现在,J2EE应用范例已经对基本的Cloudscape数据库进行了写入和读取数据的 操作,而无须SQL代码和编写代码。这是因为容器已经代表entity bean对数据存 储和检索进行了处理。container-managed persistence是一个用来描述容器处理 数据存储和检索状况的术语。本课将介绍如何重载默认的container-managed persistence实现bean-managed persistence。

Bean-managed persistence是当你使用你自己的SQL命令实现entity或session 方法时对container-managed persistence的重载。如果你需要提高性能或将多个 bean中的数据映射到数据库表格中的一行时,这种bean-managed persistence便 会发挥出作用。

本课将修改J2EE应用范例中的entity bean,使用bean-可管理的持续性。

Bean 生存周期

第3课中的BonusBean章节介 绍了container-managed BonusBean类。仅有的实现方法就是:返回bonus值的 getBonus、返回社会安全号码的getSocSec、 而ejbCreate通过传递给它的bonussocsec值来创建entity bean。容器主要负责在数据 库表中创建行,确保内存中的数据与表中行的数据一致。借助bean-managed persistence,你必须自己实现所有这些行为,实现空方法,也就是说,在容器范 例中添加JDBCTM和SQL代码。

一个session bean或entity bean由业务方法和生存周期方法组成。在这个例 子中,CalcBean有两个业务方法,即,calcBeangetRecordBonusBean 也有两个业务方法,getBonusgetSocsecCalcBeanBonusBean都 有以下的生存周期方法。业务方法由客户调用,生存周期方法由bean的容器调用。

  • setEntityContext : 首先由容器调用这个方法 将一个entity 上下文(context)对象传递给entity bean。 Entity 上下文由 容器动态更新,因此,即使entity bean在生存周期内被许多客户调用,上下文 也包含每次当前调用的数据。一个session bean有一个对应的 setSessionContext方法,执行与setEntityContext 方法相同的功能。
  • ejbCreate : 当客户在bean的home接口中调用 一个create方法时,容器将调用这个方法。对于home接口中的每个create方法, bean都有一个对应的具有相同签名特征特征(参数和返回值)的ejbCreate 方法。
  • ejbPostCreate: 在ejbCreate方法完成后,由 容器调用这个方法。对于每一个ejbCreate方法都有 一个ejbPostCreate方法,其参数与它对应的create 方法的相同。然而,ejbPostCreate没有返回值。在 用户能够使用该bean之前,使用ejbPostCreate对已 创建的bean实施所需的特殊处理。如果不需要此处理,则将这个方法设置为空。
  • ejbRemove : 当客户在bean的home接口中调用 一个remove方法时,容器将调用这个方法。本课中的J2EE应用范例在home接口 中没有提供remove方法。
  • unsetEntityContext : 在ejbRemove 被调用用来删除entity bean后,容器开始调用这个方法。只有entity bean有 一个unsetEntityContextt方法。Session bean没有 对应的unsetSessionContext方法。
  • ejbFindByPrimaryKey :当用户在bean的home接 口调用FindByPrimaryKey方法时,容器开始调用这 个方法。对于home接口中的每个find方法,bean都有一个对应的具有相同签名 特征特征(参数和返回值)的ejbFind<type >方法。
  • ejbLoadejbStore: 容器调用这些方法来同步化bean与基础数据库的状态。当客户设置或获取bean 中的数据(例如使用一个get方法)时,容器调用ejbStore 来向数据库发送对象数据,并调用ejbLoad再次读取 它。当客户调用finder方法时,容器调用ejbLoad来 利用基础数据库中的数据对bean进行初始化。
  • ejbActivateejbPassivate : 容器调用这些方法来激活 (activate)或钝化(passive)bean的状态。激活和钝化指的是将bean从临时存 储器到可用存储器之间的切入或切出,如果一个指定的bean在一段长时间里没 有被调用就可能会发生此种现象。对ejbPassivate 的实现可能包括关闭bean所使用的连接或文件,对于ejbActivate 则是重新打开连接或文件。

修改BonusBean代码

这一节将介绍bean-managed persistence BonusBean 代码。首先需要注意的是与container-managed persistence版本相比,此处有 更多的代码。

导入(import)语句

在建立与数据库的连接时,InitialContext, DataSourceConnection 接口就会被导入。PreparedStatement接口被导入,用 作创建SQL请求的模板。导入ResultSet接口来管理对 数据库查询(query)后返回数据行的访问。FinderExceptionSQLException类被导入来处理查找和数据库访问异 常。

package Beans;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EntityBean;
import javax.ejb.EntityContext;
import javax.naming.InitialContext;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import javax.ejb.FinderException;
import java.sql.SQLException;

实例变量

本课增加的实例变量可以让你建立和关闭与数据库的连接。字符串 java:comp/env/jdbc/BonusDB指示资源引用名称,也 可在使用部署工具向J2EE应用添加entity bean时再确定。在本例中,资源引用是 一个Cloudscape数据库( CloudscapeDB)的别名,这 里存储着表格数据。

然后,你将在CloudscapeDB中创建BONUS 表,在部署过程中,需要把jdbc/BonusDB映射到 jdbc/CloudscapeDB

public class BonusBean implements EntityBean {
  private EntityContext context;
  private Connection con;
  private String dbName = 
                 "java:comp/env/jdbc/BonusDB";
  private InitialContext ic = null;
  private PreparedStatement ps = null;
  private double bonus;
  private String socsec;

业务方法

本课中,除了对System.out.println的调用,业务 方法没有发生变化,所以你可以了解业务和生存周期方法在运行时被调用的顺序。

  public double getBonus() {
    System.out.println("getBonus");
    return this.bonus;
  }
  public String getSocSec() {
    System.out.println("getSocSec");
    return this.socsec;
  }

生存周期方法

这些方法包括调用System.out.println的方法,因 此,你可以了解业务方法和生存周期方法在运行时被调用的顺序。

EjbCreate

本课中的ejbCreate方法签名特征除了抛出了CreateException, 还抛出了RemoteExceptionSQLException。 由于在本课中ejbCreate方法提供了它自己的SQL代码 (不依靠容器来提供),因此需要SQLException,还 需要RemoteException来用于此方法的远程访问操作。

关于这个类需要注意的一点是,它返回一个String 值,是主关键字,但是在home接口中对本方法的声明希望收到一个Bonus 类实例。容器使用这个方法所返回的主关键字来创建Bonus 实例。

  public String ejbCreate(double bonus, String socsec)
               throws RemoteException, 
               CreateException,
               SQLException {
    this.socsec=socsec;
    this.bonus=bonus;

    System.out.println("Create Method");
    try {
//Establish database connection
      ic = new InitialContext();
      DataSource ds = (DataSource) ic.lookup(dbName);
      con = ds.getConnection();
//Use PreparedStatement to form SQL INSERT statement
//to insert into BONUS table
      ps = con.prepareStatement(
           "INSERT INTO BONUS VALUES (? , ?)");
//Set 1st PreparedStatement value marked by ? , with 
//socsec and the 2nd value marked by ?) with bonus
      ps.setString(1, socsec);
      ps.setDouble(2, bonus);
      ps.executeUpdate();
   } catch (javax.naming.NamingException ex) {
      ex.printStackTrace();
    } finally {
//Close database connection
      ps.close();
      con.close();
    }
//Return primary key
    return socsec;
  }

ejbPostCreate

这个方法与ejbCreate有相同的签名特征,但没有 实现,因为在这个简单的范例中不进行后期生成(create)处理或初始化。

  public void ejbPostCreate(double bonus, 
                            String socsec)
                            throws RemoteException,
                            CreateException, 
                            SQLException {
    System.out.println("Post Create");
  }

ejbFindByPrimaryKey

BonusBean的container-managed版本没有包括ejbFindByPrimaryKey,因为, 如果你在部署期间指定container-managed persistence并提供主关键字域,容器 可以通过它们的主关键字来找到数据库记录的位置。在本课中,BonusBean 部署了bean-managed persistence,因此,你必须实现这个方法,并抛出 SQLException。 container-managed版本只抛出 RemoteExceptionFinderException

如果利用传递给ejbFindByPrimaryKey的主关键字 确定一个记录的位置,这个主关键字值会被返回,容器便可以调用ejbLoad 方法来使BonusBean初始化,并对bonussocsec数据进行检索。

关于这个类需要注意的一点是,它返回一个String 值,是主关键字,但是在home接口中对本方法的声明希望接收到一个Bonus 类实例。容器使用这个方法所返回的主关键字来创建Bonus 实例。

public String ejbFindByPrimaryKey(String primaryKey)
              throws RemoteException,FinderException,
              SQLException {
    System.out.println("Find by primary key");
    try {
//Establish database connection
      ic = new InitialContext();
       DataSource ds = (DataSource) ic.lookup(dbName);
      con = ds.getConnection();
//Use PreparedStatement to form SQL SELECT statement
//to select from BONUS table
      ps = con.prepareStatement(
       "SELECT socsec FROM BONUS WHERE socsec = ? ");
      ps.setString(1, primaryKey);
//Use ResultSet to capture SELECT statement results
      ResultSet rs = ps.executeQuery();
//If ResultSet has a value, the find was successful, 
//and so initialize and return key
      if(rs.next()) {
        key = primaryKey;
      } else {
        System.out.println("Find Error");
      }
    } catch (javax.naming.NamingException ex) {
      ex.printStackTrace();
    } finally {
//Close database connection
      ps.close();
      con.close();
    }
//Return primary key
    return key;
  }

ejbLoad

这个方法是在ejbFindByPrimaryKey成功地被调用 后才被调用的,用来加载和检索数据,使bean数据与数据库数据同步。

  public void ejbLoad() {
    System.out.println("Load method");
    try {
//Establish database connection
      ic = new InitialContext();
       DataSource ds = (DataSource) ic.lookup(dbName);
      con = ds.getConnection();
//Use PreparedStatement to form SQL SELECT statement
//to select from BONUS table
      ps = con.prepareStatement(
        "SELECT * FROM BONUS WHERE SOCSEC = ?");
      ps.setString(1, this.socsec);
//Use ResultSet to capture SELECT statement results
      ResultSet rs = ps.executeQuery();
//If ResultSet has a value, the find was successful
      if(rs.next()){
        this.bonus = rs.getDouble(2);
      } else {
        System.out.println("Load Error");
      }
    } catch (java.sql.SQLException ex) {
      ex.printStackTrace();
    } catch (javax.naming.NamingException ex) {
      ex.printStackTrace();
    } finally {
      try {
//Close database connection
        ps.close();
        con.close();
      } catch (java.sql.SQLException ex) {
        ex.printStackTrace();
      }
    }
  }

>ejbStore

当客户在bean中设置或获取数据时对这个方法进行调用,来向数据库发送对象 数据,使bean数据与数据库数据保持同步。

  public void ejbStore() {
    System.out.println("Store method");
    try {
//Establish database connection
      DataSource ds = (DataSource)ic.lookup(dbName);
      con = ds.getConnection();
//Use PreparedStatement to form SQL UPDATE statement
//to update BONUS table
      ps = con.prepareStatement(
        "UPDATE BONUS SET BONUS = ? WHERE SOCSEC = ?");
//Set 1st PreparedStatement value marked by ?  with 
//bonus and the 2nd value marked by ?) with socsec
      ps.setDouble(1, bonus);
      ps.setString(2, socsec);
      int rowCount = ps.executeUpdate();
    } catch (javax.naming.NamingException ex) {
      ex.printStackTrace();
    } catch (java.sql.SQLException ex) {
      ex.printStackTrace();
    } finally {
      try {
//Close database connection
        ps.close();
        con.close();
      } catch (java.sql.SQLException ex) {
        ex.printStackTrace();
      }
    }
  }

ejbRemove

当客户在bean的home接口上调用remove方法时这个 方法被调用。本实例中的JavaBean客户不提供由客户调用的remove 方法来将BonusBean从它的容器中删除。下面仍然列出 了实现ejbRemove方法的代码。当容器调用ejbRemove 时,ejbRemovesocsec实 例变量中获得主关键字(socsec), 将bean从容器中删除,并删除对应的数据库 行。

  public void ejbRemove() 
              throws RemoteException {
    System.out.println("Remove method");
    try {
      DataSource ds = (DataSource)ic.lookup(dbName);
      con = ds.getConnection();
      ps = con.prepareStatement(
           "DELETE FROM BONUS WHERE SOCSEC = ?");
      ps.setString(1, socsec);
      ps.executeUpdate();
    } catch (java.sql.SQLException ex) {
      ex.printStackTrace();
    } catch (Exception ex) {
      ex.printStackTrace();
      try {
        ps.close();
        con.close();
      } catch (java.sql.SQLException ex) {
        ex.printStackTrace();
    }
  }

ejbActivate

当一个bean很长时间没有被使用时,容器将钝化该bean或将其转移到临时存储 器中,在这里,容器能够在客户调用一个bean的业务方法时再次激活这个bean。 这个方法调用entity上下文的getPrimaryKey方法,使 对这个bean进行查询的客户获得这个主关键字。当进行一个查询后,容器使用主 关键字来加载bean数据。

  public void ejbActivate() {
    System.out.println("Activate method");
    socsec = (String)context.getPrimaryKey();
  }

ejbPassivate

当一个bean很长时间没有被使用时,容器将钝化该bean或将其转移到临时存储 器中,在这里,容器能够在客户调用一个bean的业务方法时再次激活这个bean。 这个方法将主关键字设置为零,以在bean处于消极状态时释放存储空间。

  public void ejbPassivate() {
    System.out.println("Passivate method");
    socsec = null;
  }

setEntityContext

这个方法被容器调用,来初始化bean的context实 例变量。ejbActivate 方法调用context 实例变量的getPrimarykey方法来将bean从消极状态转到 激活状态。

  public void setEntityContext(
                  javax.ejb.EntityContext ctx){
    System.out.println("setEntityContext method");
    this.context = ctx;
  }

unsetEntityContext

在调用了ejbRemove方法将entity bean删除后,容 器调用这个方法来将context实例变量设置为零。只有 entity bean有unsetEntityContext方法。

  public void unsetEntityContext(){
    System.out.println("unsetEntityContext method");
      ctx = null;
  }
}

修改CalcBean和JbonusBean代码

由于BonusBean提供它自己的SQL代码,因此必须修 改CalcBean.calcbonus方法(创建 BonusBean实例),来抛出java.sql.SQLException。 下面是修改的一种方法:

public class CalcBean implements SessionBean {
  BonusHome homebonus;

  public Bonus calcBonus(int multiplier, 
                         double bonus, String socsec)
                         throws RemoteException,
                         SQLException,
                         CreateException {

    Bonus theBonus = null;
    double calc = (multiplier*bonus);

    try {
      InitialContext ctx = new InitialContext();
      Object objref = ctx.lookup("bonus");
      homebonus = (BonusHome)
                  PortableRemoteObject.narrow(
                  objref, BonusHome.class);
    } catch (Exception NamingException) {
      NamingException.printStackTrace();
    }

//Store data in entity Bean
    theBonus=homebonus.create(calc, socsec);
    return theBonus;
  }

必须修改JbonusBean类,来捕获被CalcBean抛出的 SQLExceptionn。DuplicateKeyExcpetionCreateException的一个子类,因此,它会被 catch (javax.ejb.CreateException e)语句所捕获。

  public double getBonusAmt() {
    if(strMult != null){
      Integer integerMult = new Integer(strMult);
      int multiplier = integerMult.intValue();
      try {
        double bonus = 100.00;
        theCalculation = homecalc.create();
        Bonus theBonus = theCalculation.calcBonus(
                         multiplier, bonus, socsec);
        Bonus record = theCalculation.getRecord(
                       socsec);
        bonusAmt = record.getBonus();
        socsec = record.getSocSec();
      } catch (java.sql.SQLException e) {
        this.bonusAmt = 0.0;
        this.socsec = "000";
        this.message = e.getMessage();
      } catch (javax.ejb.CreateException e) {
        this.bonusAmt = 0.0;
        this.socsec = "000";
        this.message = e.getMessage();
      } catch (java.rmi.RemoteException e) {
        this.bonusAmt = 0.0;
        this.socsec = "000";
        this.message = e.getMessage();
      }
      genXML();
      return this.bonusAmt;
    } else {
      this.bonusAmt = 0;
      this.message = "None.";
      return this.bonusAmt;
    }
  }

创建数据库表

因为本例中使用了bean-managed persistence,因此必须在CloudscapeDB 数据库中创建BONUS数据库表。可以借助container- managed persistence创建该表。

为了简便,数据库表采用两种脚本创建:createTable.sqlcloudTable.sh(Unix)或cloudTable.bat (Windows/NT)。 对于这个范例,createTable.sql 脚本要放进你的~/J2EE/Beans目录, cloudTable.sh(Unix)或cloudTable.bat (Windows/NT)脚本要放进你的~/J2EE目录。

为了执行该脚本,需要进入Beans目录并键入:

Unix:

../cloudTable.sh

Windows/NT:

..\cloudTable.bat

createTable.sql

在本课下载代码中提供了这个文件。

drop table bonus;

create table bonus
(socsec varchar(9) constraint pk_bonus primary key,
bonus decimal(10,2));

exit;

cloudTable.bat

在本课的下载代码中提供了这个文件。

rem cloudTable.bat
rem Creates BONUS table in CloudscapeDB.
rem
rem Place this script in ~\J2EE
rem To run: cd ~\J2EE\cloudTable.sh
rem
rem Change this next line to point to *your*
rem j2sdkee1.2.1 installation
rem
set J2EE_HOME=\home\monicap\J2EE\j2sdkee1.2.1
rem
rem Everything below goes on one line
java -Dij.connection.CloudscapeDB=
jdbc:rmi://localhost:1099/jdbc:cloudscape:
CloudscapeDB\;create=true -Dcloudscape.system.home=
%J2EE_HOME%\cloudscape -classpath  
%J2EE_HOME%iib\cloudscape\client.jar;
%J2EE_HOME%iib\cloudscape\ tools.jar;
%J2EE_HOME%iib\cloudscape\cloudscape.jar;
%J2EE_HOME%iib\cloudscape\RmiJdbc.jar;
%J2EE_HOME%iib\cloudscapeiicense.jar;
%CLASSPATH% -ms16m -mx32m 
COM.cloudscape.tools.ij createTable.sql

cloudTable.sh

在本课的下载代码中提供了这个文件。

#!/bin/sh
#
# cloudTable.sh
# Creates BONUS table in CloudscapeDB.
#
# Place this script in ~\J2EE
# To run: cd ~\J2EE\cloudTable.sh
#
# Change this next line to point to *your*
# j2sdkee1.2.1 installation
#
J2EE_HOME=/home/monicap/J2EE/j2sdkee1.2
#
# Everything below goes on one line
java -Dij.connection.CloudscapeDB=jdbc:rmi:
//localhost:1099/jdbc:cloudscape:CloudscapeDB\;
create=true -Dcloudscape.system.home=
$J2EE_HOME/cloudscape -classpath
$J2EE_HOME/lib/cloudscape/client.jar:
$J2EE_HOME/lib/cloudscape/tools.jar:
$J2EE_HOME/lib/cloudscape/cloudscape.jar:
$J2EE_HOME/lib/cloudscape/RmiJdbc.jar:
$J2EE_HOME/lib/cloudscape/license.jar:
${CLASSPATH} -ms16m -mx32m 
COM.cloudscape.tools.ij createTable.sql

移除JAR文件

我们必须用新的entity bean编码更新bean JAR文件。 如果两个bean都在一个 JAR文件中,则必须删除2BeansJar并创建一个新的。添加 CalcBean的步骤与“ 用session bean创建JAR”的步骤相同。添加BonusBean 的步骤略有不同,具体如下。

如果两个bean在不同的JAR文件中,则需要删除带BonusBean 的JAR文件,并创建一个新的JAR文件。

这些指令就在你把BonusBean接口和类添加到JAR文 件的地方。

EJB JAR :

  • 点击“添加”(“内容”窗口旁边的那一个)。
  • 使Beans目录显示其内容。
  • 选择Bonus.class
  • 点击“添加”。
  • 选择BonusBean.class
  • 点击“添加”。
  • 选择BonusHome.class
  • 点击“添加”。

EnterpriseBean JAR类:

  • 确保能够在显示栏中看到Beans/Bonus.class, Beans/BonusHome.classBeans/BonusBean.class
  • 点击 “OK”。

EJB JAR :

  • <点击“下一步”。

一般项目 :

  • Beans.BonusBean是类别名称, Beans.BonusHome是home接口,Beans.Bonus 是远程接口。
  • 输入BonusBean作为显示名称。
  • 点击Entity
  • 点击“下一步”。

Entity 设置:

  • 选择Bean-managed persistence
  • 主关键字类为java.lang.String,主关键字名 称为socsec。注意,主关键字必须是一个类类型。原始类型对于主关键字无效。
  • 点击“下一步”。

环境项目:

  • 点击“下一步”。 这个简单的entity bean没有使用这个属性(环境项目)。

Enterprise Bean 引用:

  • 点击“下一步”。

资源引用:

  • 点击“下一步”。
  • 在“Coded Name”下的第一栏中键入 jdbc/BonusDB。 确保类型为 javax.sql.DataSource并且Authentication 是容器。
  • 点击“下一步”。

安全:

  • 点击“下一步”。 该简单entity bean不使用安全角色。

事务管理 :

  • 选择Container-managed transactions (如果 还没有被选择)。
  • 在下面的列表中需要create, findByPrimaryKey, getBonusgetSocSec。 这就是说,容器在运行这些方法之前启动新的事务流程。这个事务流程正好在 这些方法结束后提交。可以在“企业JavaBeans开发人员手册”中的第六章中获 得有关这些事务流程的更多信息。
  • 点击“下一步”。

检查设置:

  • 点击“完成”。

检查窗口:

  • 选择2BeansApp, 点击“JNDI 名称”。
  • CalcBean分配calcsBonusBean分配bonusjdbc/BonusDBjdbc/Cloudscape

验证和部署J2EE应用

在部署应用之前最好能够运行验证器。验证器将挑出应用组件中的错误,如编 译器未曾捕获的丢失的enterprise bean方法。

:如果在验证或部署时出现 存储的错误,则需要关闭所有程序,重新启动服务器和工具。

验证:

  • 选定2BeansApp, 从“工具”菜单中选择“验 证器”。
  • 在弹出的对话框中,点击“OK”。 窗口将通知 你测试成功。
  • 关闭验证器窗口,准备部署应用。
注: 在Version 1.2.1软件中, 你可能会得到一个 tests app.WebURI的错误。这表明, 在WAR文件创建过程中,部署工具没有将 .war扩展名附加给WAR文件。 这是一个小的错误,不影响J2EE应用的部署。

部署:

  • 从“工具”菜单中选择“部署应用”。 会弹出一个“部署 BonusApp”对话框。
  • 验证“目标服务器”选项或者是本地主机或是运行J2EE服务器的主机的名称。
  • 选定Return Client Jar。选定后将创建一个带有entity bean所需部署信息的一个JAR文件。
  • 点击“下一步”。
  • 确定CalcBean的JNDI名称为 calcsBonusBean的 JNDI名称为bonus。 如果不是,则需要将JNDI名 称键入,然后按下回车键。
  • 点击“下一步”。 确定“前后文根”名称显示为 BonusRoot。 如果不是,则需要将其键入,然后按 下回车键。JSPRoot .
  • 点击“下一步”。
  • 点击“完成”开始部署。此时,会弹出一个显示部署操作状态的对话框。
  • 完成后,点击“OK”。

运行J2EE应用

web 服务器的运行端口默认为8000。 若要打开bonus.jsp 页面,可进入以下地址,http://localhost:8000/JSPRoot/bonus.jsp, 这是部署工具放置JSP页面的位置。

  • 填入社会安全号码和乘数。
  • 点击“提交”按钮。Bonus.jsp会对传入的数据 进行处理,并返回一个带bonus计算值的HTML页面。

在每次试图访问数据库时,J2EE服务 器输出可能会显示出以下的消息。意思是,在访问数据库之前没有提供用户名和 密码。 你可以忽略这个信息,因为在进入Cloudscape数据库时不需要用户名和密 码,无论是否出现这个信息,本范例都能正常运作。

Cannot find principal mapping information for data source with JNDI name jdbc/Cloudscape

下面是J2EE服务器输出的“清洁”版本(以上的信息已被编辑中删除)。

setEntityContext method
Create Method
Post Create
setEntityContext method
Find by primary key
Load method
getBonus
Store method
Load method
getSocSec
Store method
Find by primary key
Load method
getSocSec
Store method
Load method
getBonus
Store method

<?xml version="1.0"?>
<report>
  <bonusCalc ssnum="777777777" bonusAmt="300.0" />
</report>

多信息

你可以进入以下网址获得有关entity beans和bean-managed persistence的更 多信息:

http://java.sun.com/j2ee/j2sdkee/techdocs/guides/ejb/html/Entity.fm.html


可以从以下网址中获得有关数据库连接的更多信息:
http://java.sun.com/j2ee/j2sdkee/techdocs/guides/ejb/html/Database.fm.html

[TOP]

 

常见问答
下载中心
产品简介
 
 
Solaris论坛
 
   
 
null