680 likes | 1.03k Views
实体 Bean 教程. 教程实例环境. Jbuilder 7 for Weblogic Borland JDataStore Weblogic7.01 一台速度比较快的电脑(512 M 内存,赛羊1 G). 实体BEAN的作用. 实体 Bean 是用来代表数据的。 Session Bean 可以通过 JDBC 直接存取数据库。为什么还要多加一层实体 bean 呢? JDBC 直接存取: 各种数据库操作方法不同,不利移植 各种数据库事务、安全方法不同 如果能统一处理事务、安全岂不更好?. 实体 Bean 的位置. SessionBean.
E N D
教程实例环境 • Jbuilder 7 for Weblogic • Borland JDataStore • Weblogic7.01 • 一台速度比较快的电脑(512M内存,赛羊1G)
实体BEAN的作用 • 实体Bean是用来代表数据的。 • Session Bean可以通过JDBC直接存取数据库。为什么还要多加一层实体bean呢? • JDBC直接存取: • 各种数据库操作方法不同,不利移植 • 各种数据库事务、安全方法不同 • 如果能统一处理事务、安全岂不更好?
实体Bean的位置 SessionBean Other Clients 实体bean增加了一个 中间层。客户不直接 存取数据库,而是由 容器存取,从而获得 容易使用的安全和事务 ,并且跨平台易移植。 Entity Bean Database
实体Bean和数据库表的关系 某个实体Bean 数据表
实体Bean和数据库之间的同步 ejbLoad(自动调)ejbStore(自动调) Entity bean 容器 load store 数据库和bean同步由 容器自动完成! DB
实体bean的生成流程 1 create 2 ejbCreate client Home Entity Bean Instance 4返回pk值 6返回 EJBObject 5 EJBObject 3 取数据 remote Container database
制作一个实际的BMP • 任务:帐号管理,提款,存款,查余额
第一部份: 远程接口 • Account.java • Interface Account extends EJBObject{ public void deposit(xxx) public void withdraw(xxx) 一批业务方法外加一堆的get/set 方法。
第二部份:Home接口 AccountHome.java用于创建EJB对象 Interface AccountHome extends EJBHome{ Account create(帐号,用户名) Account findByPrimaryKey(AccountPK key) Collection findByOwnerName(用户名)
第三部份:主键类 • 主键类提供某bean的唯一标识 • AccountPk.java • Public class AccountPK implements ..{ • String id • 构造方法+toString()+hashCode()+equals(Object ob)方法。
第四部份:核心逻辑类 • AccountBean.java • 核心类分: • 1 数据域部份 • 2 业务方法具体实现(在remote里指明) • 3 容器自动调用方法实现 • 4 查找方法的实现(在Home里有的)
4.1数据域部份 • Public EntityContext ctx; • Public String id; • Public string name; • Public double balance;
4.2业务方法部份 • Public void deposit(double amt){ • balance+=amt} • Public void withdraw(…){ • Balance-=amt}; • 大家看到,bean的业务方法不直接写数据库,写是由ejbLoad/Store自动进行的
4.3容器自动调用的方法。 • ejbLoad(){ • AccountPk pk= ctx.getPrimaryKey(); • “Select id,name,balance from xxx where id = pk.getid();” • Id=rs.getString(“id”) • Name=rs.getString(“name”); • Balance=rs.getDouble(“balance”);
4.3 • ejbLoad中用户需要做以下事情: • 使用jdbc直接打开数据表 • 用select语句取出所需要的记录 • 将记录装入当前bean。 • 关闭数据库连接
4.3 • ejbStore{ • “Update xxx set name=? Balance= ? Where id=?” • 其中的id当然也是从pk中得到的。也就是把指定pk的记录写库
4.3 • setEntityContext(EntityContext ctx){ • This.ctx=ctx; • 从容器取得本bean的上下文,然后从外面调用内部方法而取得容器的安全性
4.3 • ejbRemove • 只要用delete 方法把主键相应的记录直接删除就行了。用户打开连接,执行delete,然后返回
4.3 • ejbCreate(id,name) • { • 连接数据表,使用insert语句插入数据库一条记录。 • 返回一个新的 pk值 • }
Public AccountPk ejbFindByPrimaryKey{ • 直接使用select 语句返回值。} • Public Collection ejbFindByOwnerName(name) • 直接使用vector返回pk的集合
EJB字段:和数据库中字段对应 业务方法deposit等,操作ejb字段,不直接存取DB ejbRemove->用户调用,实际上是delete数据 ejbLoad容器调用,实际上是select数据装入bean ejbStore容器调用,实际上是update数据更新 ejbCreate,用户调用,向表中新插入数据insert ejbFindBy…方法,用户调用,select返回pk
客户端 • Public class client • Context ctx = new InitialContext(..) • Object obj=ctx.lookup(“AccountHome”); • AccountHome home=(AccountHome) PortableRemoteObject.narrow(obj,AccountHome.class) • Account= Home.create(“0001”,”zenghai”); • Account.getPrimarykey • Account.getBalance,withdraw,remove…
部署客户端 • <ejb-name><home><remote><ejb-class>略,差不多的。 • <persistance-type> BEAN</..>表明是bmp • <prim-key-class> ..AccountPk • <reentrant> false</..>
BMP的特性: • BMP在用户和数据间加了一个中间层 • 用户看到某个bean,操作这个bean等于操作数据库,且安全可靠。 • 这个bean就是一个bmp的bean。实际的数据库操作由用户编写,容器调用。特别是ejbCreate,ejbRemove,ejbLoad,ejbStore。 • 比较烦人啊。。
CMP 更简单抽象的实体bean
本节操作任务: • 创建一个实体bean,它代表一个雇员数据表。 • 再创建一个会话bean,它调用这个实体bean,向实体bean要数据。 • 再创建一个客户端,它调用这个会话bean,从而显示雇员表中的某个数据。
Step1准备工作 • Jbuilder7和weblogic准备好。Jbuider7必须已经装好JDataStore。如果没有就用access,比较麻烦些。 • 启动jbuilder7,新建项目,比如叫eejb。然后在里面新建一个ejb模块。比如叫testEntMod
Step2 从外部倒入数据库 • 点击左侧窗口的testEntMod结点,在右窗口下选择ejbDesigner图形化编缉器。 • 在空白处右击,选择import schema from database • Driver在下拉中选择com.borland.datastore.jdbc.DataStoreDriver • Url选择local的,全称是jdbc:borland:dslocal:D:\JBuilder7\samples\JDataStore\datastores\employee.jds • 用户名密码自己选,要记牢,等会用 • Jndi名字要记牢,等会用
Step3 创建cmp • 点击确定,jbuilder左下角出现DataSource窗口,里面有一堆的数据表,现在点中Employee,然后右击。 • 选择create cmp entity bean 2.0 • 等一会儿,右边窗口出现图形化的CMP, • 创建成功。请观察这个bean。。
Step4 建立相应会话Bean • 在设计器上右键,选择sessionBean,把这个sessionBean起名为EmployeeSes。 • 再加一个方法名字叫getEmpName,返回String,带个参数是Short empNo。
Step5 加入代码,在session中存取entity bean • String empName = "name not found"; • try { • javax.naming.Context context = new javax.naming.InitialContext(); • Object object = context.lookup("java:comp/env/ejb/Employee"); • EmployeeHome empHome = (EmployeeHome) • javax.rmi.PortableRemoteObject.narrow(object,EmployeeHome.class); • Employee emp = empHome.findByPrimaryKey(empNo); • empName = emp.getFirstName() + " " + emp.getLastName(); • } • return empName;
Step6 在Sessionbean中加入对entitybean的引用 • 双击左侧的EmployeeSes这个bean,在右窗口下面选择ejb Local Reference,选择add,新加一个引用。引用的名字取成ejb/Employee。如果不这么写,前面getEmpName方法就会出错。
Step7 创建客户端测试程序 • 为EmployeeSes建立一个客户端。 • 建立后请先改动Main方法为: • EmployeeSesTestClient client = new EmployeeSesTestClient(); • try { • client.create(); • String empName = client.getEmpName(new Short("2")); • System.out.println("Employee Name from the Test Client is = " + empName); • } • catch (Exception ex) { • ex.printStackTrace(); • }
Step8启动相应服务器 • 在项目运行属性里加两个配置 • Server配置运行weblogic • Client配置运行客户端程序TestClient • 在jbuilder里启动weblogic
Step9 配置数据源的缓冲池 • 进7001/console的weblogic控制台 • 选择service的jdbc,配新的jdbc pool • Url就是一开始的jdbc:borland:dslocal:D:\JBuilder7\samples\JDataStore\datastores\employee.jds • Driver就是com.borland.datastore.jdbc.DataStoreDriver
Step9 配置数据源的缓冲池 • 在properties里输入 • User=test • Password=test。 • 这段和您开始import时候的选择对应。 • 点击apply
Step 10调节缓冲性能 • 进旁边的connection • 初始设成2,最大设成5,增加设成1 • 启动jdatastore服务器 • 进旁边的targets,选择myserver到右边,点击apply。。。。。
Step11 应对意外情况 • 上节apply必然失败,因为jdatastore没有在weblogic里配置好。回到jbuilder。 • 在configserver里,在配置lib 里,weblogic启动时加上类库 • [D:/JBuilder7/lib/jdsserver.jar] • 重新启动weblogic,可以配置pool成功。
Step 12配置支持事务的数据源 • 进jdbc的txDataSource • 新建数据源,名字是demoDataSource。这个名字必须和import时起的jndiName一样,否则等着出错。 • Pool名就是你刚建的pool,比如demoPool • 在target里把它应用到服务器上。
Step13测试数据源 • 回jbuilder,关掉weblogic • 重新启动weblogic,控制台上没错的话 • 就okay。 • 有错就trouble shooting
Step 14运行客户端 • 天哪。。终于运行出来了! • 看看输出的结果是什么? • 想想调用的过程?
CMP • BMP的特点: • 虽然ejbLoad,ejbStore是由容器自动调用的,但是一个实体bean怎么和数据库打交道还是需要“硬”编码。 • Select update insert delete实际上都得写上。 • BMP的东西实际上还是和具体数据库相关的。
引入CMP的考虑 • Bmp编码中,逻辑和持久化表示混合 • Cmp试图分离逻辑和持久化表示。 • 结论: • 在实体bean类中,不写任何的jdbc具体语句。具体存取数据库代码由容器替您生成好。
CMP图示 一个子类,由容器生成,实现具体的存取代码 实体bean超类,包含数据逻辑,自己写
CMP的bean不包含字段定义 • 没有诸如String id,String Name之类的。这些东西在子类里由容器产生。 • 不包含字段的原因是容器可能会外加一些辅助的字段,您并不需要关心这些。
一个bmp的类可能是这样的 • Class xxx { • public String id… • public String getId(){ • return id • } • 在cmp中,get/set代码由容器生成。在父类里,不需要硬编码,定义个abstract类就可以了。
Abstract的父类 public abstract class CartBean implements EntityBean { • public abstract float getXXX(); • public abstract float getXXXX(); • public float getTotal(){ • return this.getXXX()+this.getXXXX()} • }//这里也可以有abstract的set方法。
实际代码从何而来? • 类里用abstract方法描述set/get • 实际代码由容器生成,容器怎么生成? • 由您用部署文件进行描述 • <cmp-version>2.x • <abstract-schema-name> AccountBean • <cmp-field> <field-name>Id</></> • <primkey-field> id </primkey-field>
解释部署文件 • 部署文件说明了abstract的类和数据库字段的对应关系。 • 每个cmp-field域就是持久化域,每个域都要在子类中生成get/set方法,所以域名必须和get/set一致。 • Abstract void setName()则cmp-field就应该是name。这样容器就知道对应关系了