我想搞一个关于ejb的讨论。欢迎大家进来发言。(我抛了一块砖,就等大家的玉了)(300分)

  • 主题发起人 主题发起人 小猪
  • 开始时间 开始时间
hehe..和我的书一样,老大,我现在正头疼呢!
 
小猪,你在东软吗?
想问一下,做多层,那种架构好。
ejb,corba,com/dcom
 
to:雨人
恐怕目前就国内的开发实力来看,dcom是一个比较好的选择。
corba目前国内据我所知深圳平安保险的应用是比较成功的,
ejb我还没有听到过真正算得上非常成功的应用。
 
大量查询应用session bean,有优化的,关于entity bean,看下文:
一条记录对应一个ENTITY,简单可行,但最好看以下的优化原则!--呵呵
优化entity Bean的七条准则
作者:Akara Sucharitakul
日期:May 2001
翻译:lava
转载自: http://developer.java.sun.com/developer/technicalArticles/ebeans/
sevenrules
注:翻译中在保证转达原文内涵的前提下进行了一些简化,如果有兴趣可以通过以上网
址阅读英文原文。翻译中难免纰漏错误之处,欢迎指正。欢迎讨论该技术主题。
[正文]
entity bean为在应用程序和设计中描述持久化商业对象(persistent business objec
ts)提供了一个清晰的模型。在java对象模型中,简单对象通常都是以一种简单的方式
进行处理但是,很多商业对象所需要的事务化的持久性管理没有得到实现。entity bea
n将持久化机制封装在容器提供的服务里,并且隐藏了所有的复杂性。entity bean允许
应用程序操纵他们就像处理一个一般的java对象应用。除了从调用代码中隐藏持久化的
形式和机制外,entity bean还允许EJB容器对对象的持久化进行优化,保证数据存储具
有开放性,灵活性,以及可部署性。
在一些基于EJB技术的项目中,广泛的使用OO技术导致了对entity bean的大量使用,SU
N的工程师们已经积累了很多使用entity Bean的经验,这篇文章就详细阐述的这些卡发
经验:
*探索各种优化方法
*提供性能优化和提高适用性的法则和建议
*讨论如何避免一些教训。
法则1:只要可以,尽量使用CMP
CMP方式不仅减少了编码的工作量,而且在Container中以及container产生的数据库访问
代码中包括了许多优化的可能。Container可以访问内存缓冲中的bean,这就允许它可以
监视缓冲中的任何变化。这样的话就在事物没有提交之前,如果缓存的数据没有变化就
不用写到数据库中。就可以避免许多不必要的数据库写操作。
另外一个优化是在调用find方法的时候。通常情况下find方法需要进行以下数据库操作

查找数据库中的纪录并且获得主键
将纪录数据装入缓存
CMP允许将这两步操作优化为一步就可以搞定。[具体怎么做我也没弄明白,原文没有具
体阐述]
法则2:写代码时尽量保证对BMP和CMP都支持
许多情况下,EJB的开发者可能无法控制他们写的bean怎么样被部署,以及使用的conta
iner是不是支持CMP.
一个有效的解决方案是,将商业逻辑的编码完全和持久化机制分离。再CMP类中实现商业
逻辑,然后再编写一个BMP类,用该类继承CMP类。这样的话,所有的商业逻辑都在CMP类
中,而持久化机制在BMP中实现。
[我觉得这种情况在实际工作中很少遇到,但是作者解决问题的思路值得学习]
法则3:把ejbStore中的数据库访问减小到最少。
如果使用BMP,设置一个缓存数据改变标志dirty非常有用。所有改变数据库中底层数据的
操作,都要设置dirty,而在ejbStore()中,首先检测dirty的值,如果dirty的值没有
改变,表明目前数据库中的数据与缓存的一致,就不必进行数据库操作了,反之,就要
把缓存数据写入数据库。
法则4:总是将从lookup和find中获得的引用进行缓存。(cache)
引用缓存对session bean和entity bean 都是适用的。
通过JNDI lookup获得EJB资源。比如DataSource,bean的引用等等都要付出相当大的代价
。因此应该避免多余的lookup.可以这样做:
l将这些引用定义为实例变量。
l从setEntityContext(session Bean使用setSessionContext)方法查找他们。
SetEntityContext方法对于一个bean实例只执行一次,所有的相关引用都在这一次中进
行查找,这样查找的代价就不是那么昂贵了。应该避免在其他方法中查找引用。尤其是
访问数据库的方法:ejbLoad()和ejbStore(),如果在这些频繁调用的方法中进行DataSo
urce的查找,势必造成时间的浪费。
调用其他entity bean的finder方法也是一种重量级的调用。多次调用finder()方法的代
价非常高。如果这种引用不适合放在setEntityContext这样的初始化时执行的方法中执
行,就应该在适当的时候缓存finder的执行结果。只是要注意的是,如果这个引用只对
当前的entity有效,你就需要在bean从缓冲池中取出来代表另外一个实体时清除掉这些
引用。,这些操作应该在ejbActivate()中进行。
法则5:总是使用prepare statements
这条优化法则适用于所有访问关系数据库的操作。
数据库在处理每一个SQL Statement的时候,执行前都要对Statement进行编译。一些数
据库具有缓存statement和statement的编译后形式的功能。数据库可以把新的Statemen
t和缓存中的进行匹配。然而,如果要使用这一优化特性,新的Statement要必须和缓存
中的Statement完全匹配。
对于Non-prepared Statement,数据和Statement本身作为一个字符串传递,这样由于前
后调用的数据不同而不能匹配,就导致无法使用这种优化。
而对于prepared Statement,数据和Statement是分开传递给数据库的,这样Statement就
可以和cache中已编译的Statement进行匹配。Statement就不必每次都进行编译操作。从
而使用该优化属性。
这项技术在一些小型的数据库访问中能够减少Statement将近90%的执行时间。
法则6:完全关闭所有的Statement
在编写BMP的数据库访问代码时,记住一定要在数据库访问调用之后关闭Statement,因为
每个打开的Statement对应于数据库中的一个打开的游标。
法则7:避免死锁
关于作者:
Akara Sucharitakul:Sun公司内部包括Ecperf benchmark在内的多个J2EE服务器端应用
的开发者之一。他有至少5年使用java技术的开发经验,并且从J2EE技术的初期就一直从
事此方面的开发工作。
 
http://www.waptools.org/zippdf/ejb_design_patterns.zip
 
Deciding whether EJB is appropriate
By Ed Roman
excerpted from the new "Mastering Enterprise JavaBeans 2nd edition" book
September 2001
Discuss Article here.

Motivation
A recent Gartner Group report cited companies overspent $1 billion on EJB last
year, when they could have just gotten by with Servlets/JSPs. This motivates
our next discussion: once you've decided whether server-side Java is the way
to go, you then
need to make the all-important decision: are you actually
going to use EJB on this project? Or is EJB overkill?
Example
As a motivational example, consider an E-commerce site that has involved
business processes. When you buy something on an E-Commerce site, the site
needs to:
Validate your credit card

Debit your credit card

Perhaps run some anti-fraud checking algorithms

Check inventory

Send a confirmation email

Submit the order

Fulfill the order

Track the order afterwards

Handle returns
You can still achieve all of this by using vanilla Servlets and JSPs. For
example, you could have the Servlets and JSPs call Java classes. Those Java
classes perform your business logic. In fact, there are three scenarios
that we can consider when it's possible to use Java classes rather than EJB
components:
In a browser client web-based system with Servlets and JSPs, you could use
Java classes rather than EJB components.
In a web services system where business partners call your Servlets and JSPs
using XML/HTTP, you can also use Java classes rather than EJB components
(see http://www.TheServerSide.com for a whitepaper on how to build web
services using J2EE).
In a 2-tier client/server system such as a Java applet or Java application
connecting to a server, you could again use Servlets and JSPs on the server.
The thick client could communicate with the server via HTTP, which easily
navigates through firewalls (compared to IIOP, whichdo
esn't). Behind the
Servlets and JSPs could be Java classes instead of EJB components.
NOTE: A Servlet/JSP HTTP layer is only important if the users of your system
are going to be behind firewalls, such as anonymous Internet clients, business
partners, or other departments within your organization. It's also important
if your thick client is located across the Internet, because HTTP is a
lightweight protocol that travels across the Internet easily. If there is no
firewall issue, or if your users are not located across the Internet
(but rather are on your local area network) you could get rid of your HTTP
layer and connect the client to EJB components directly. In this case, the
EJB value proposition is very strong, because EJB allows the client to call
the server using intuitive method names, removes the need to perform XML mar
shaling, and gives you automatic remotability and load-balancing.

The Fear, Uncertainty, anddo
ubt
So howdo
you decide which is the right paradigm? Let's start out with the
reasons that most people think are important for deciding between EJB and
Java classes, but are actually not important at all.
EJB server cost. The major J2EE server vendors, such as IBM, BEA, and Oracle,
do not sell their EJB layer separately from their Servlet/JSP layer. They sell
a single "J2EE server" which bundles both layers. So if you go with a market
leader, then
you're probably going to buy an EJB server whether you like it
or not. The only way to avoid this cost is to purchase an open-source or
inexpensive Servlet/JSP implementation. This is a viable option, this is not
recommended for major deployments. Why? Because the cost of the J2EE server
is often a drop in the bucket compared to the total cost of the project.
If the serverdo
esn't work out, consider all the retraining you'll need to
pay for, and the code you may need to rewrite if the servers use different
versions of the J2EE specifications. Consider the difficulty in hiring skilled
professionals if youdo
n't go with a market leader, the cost of re-learning
how to tune your new server, and the cost of learning how to administer that
new server. The cost of the application server should not be an issue for most
serious deployments--most major vendors are charging very reasonable fees,
far less than the $50,000 per processor that was charged back in the day.
Rather, you should consider whether an EJB layer or a Java class layer is
appropriate for your project. The professional services fees--we call it geek
time--tends to dwarf the application server cost.
Resource pooling. Some people think that only EJB can give you resource
pooling. Not true. Almost all the major J2EE server vendors allow you to get
connection pooling and thread pooling whether you use Servlets/JSPs or EJB
components.
Clean separation of business logic and presentation logic. EJB is nice because
it enforces a separation of presentation logic (Servlets and JSPs) from
business logic (EJB components). We like this because in the future we can
support different types of presentation logic, such as a WAP enabled phone,
or an XML data stream client from a business partner. But you can achieve the
same results with Java classes instead of EJB components as well. You just
need to enforce some coding best-practices in your organization about the
proper usage of Java classes as a business layer façade.
Deciding the right way
Now that we've blown away the FUD (Fear, Uncertainty, anddo
ubt), here are
the real reasons to use EJB over Java classes:
Your system is built faster and more reliably. EJB components benefit from
declarative middleware, such as instance pooling, transactions, security,
container-managed persistence, container-managed relationships, and data
caching. If you used regular Java classes, you'd need to write this middleware
yourself over time. Eventually you might find that you have your own middleware
framework. That 'framework' is a fancy word for building your own home-grown
application server. The framework needs to be tested, debugged, features need
to be added. This is a non-trivial task indeed. Can you honestly state that
your staff is capable of building a better application server than the market
leaders who specialize in middleware?
It is easier to hire new employees. If you build your own custom framework
using Java classes, then
newhires need to be trained on this framework. If
your framework is complex, then
you can no longer look for "EJB" on a resume
when hiring a developer and expect them to be productive on your system.
You benefit from the best practices the world is building around EJB. You can
figure out how to optimize your system by reading articles on the Internet, or
picking up a book on EJB best practices, such as Floyd Marinescu's "EJB Design
Patterns" book. This global knowledge base is not at your disposal with a
proprietary Java class framework.
You can have different user interfaces. You can reuse the same EJB component
layer for a thick client as well as a Servlet/JSP client. With Java classes,
you cannot achieve this because Java classes are not remotely accessible. If
you wrapped those Java classes in RMI objects, you'd need to invent your own
load-balancing, instance pooling, and fail-over.
You can work with industry-standard tools to rapidly develop your system.
While in the short run you may think that Java classes are going to make it
faster to develop than writing all those files that comprise an EJB component,
in reality there are many tools around that help streamline the EJB
development process. There are command-line tools that generate the files you
need, there are IDEs that help you build EJB components, and there are UML
editors that help you generate EJB components from UML diagrams. See
http://www.TheServerSide.com for more.
You can separate your web tier and application server. If you require your
business logic to be protected by a firewall, then
you can deploy the web
server and application server on separate machines and stick a firewall in
the middle.

And here are the real reasons not to use EJB:
You can't deal with the limitations of EJB. Examples include threading,
static variables, and native code. Most companies can deal with this, because
there are good reasons why the restrictions exist. But if (for example) you
need to have a multi-threaded engine, and you can't deal with the EJB paradigm
of load-balancing across single-threaded instances, then
EJB is not a good fit
for you. EJB is a square peg--don't try to stick it into a round hole.
Your have existing skillsets or investments in a working technology. For
example, if your developers are proficient in CORBA, then
great--why not
stick with it? As an anecdote, The Middleware Company consulted with one of
our clients who wrote a CORBA application that assisted with mapping the human
genome. It worked well with CORBA, and they had no major complaints, and so
we recommended they stick with CORBA and avoid the EJB hype.
Your application is a big GUI to a database. If you are just a big GUI to a
database--heavy on data logic but no business logic--you could achieve a
deployment easily using JSPs with tag libraries connecting to a database
via JDBC.
Your application is simple. If you are prototyping, building a simple system,
or developing a one-off application that will not evolve over time, EJB may be
overkill.

Summary
In summary, it is a perfectly valid strategy to use EJB, or to use Java classes
. Just make sure you know why you're making the decision, and that youdo
it
for the right reasons.
 
开始有货了...
 
本文主要介绍一种数据库相关类的设计模式。并介绍在J2EE框架中的具体实现,以及在
事务处理方面的一些考虑。
一、设计模式简介
  在开发J2EE应用程序时,通常是要找出应用程序中涉及到的各种信息,比如一个公
司的产品目录,或一个网站的用户信息,我们会将这些信息放在数据库里。
  在通常的设计中,我们要分析这些数据的属性和关系,然后进行数据库的逻辑设计
,把各种信息用不同的表来存储。比如,要开发一个图书信息查询系统。可以创建下面
两个表来分别表示书和出版社。
  table Book (ID, Name, ISBN, Author, PublisherID, Price, Volume)
  table Publisher (ID, Name, Telephone, Address, Postcode)
  表Book包含了ID,书名,书号,作者,出版社ID,价格,页数。表Publisher包含I
D,社名,电话,地址,邮编。这两个表通过出版社ID相关。
  下面我们来介绍一种数据库相关类的设计的模式。
  数据库相关类可以分成实体类(Entity Class)和会话类(Session Class)。
  实体类对应于一个表的记录的封装,也就是该类的一个实例对应于表中的一个记录
。而且,该类中的属性和记录中的字段是一一对应的。
  会话类对应于对一个表中的所有记录的操作。比如增加一条记录,删除一条记录,
查找记录和更新一条记录。
  通过使用这种设计模式,使程序更加模块化,便于开发和维护。当然,也可以使用
其他设计模式。
二、程序实现
  在具体实现上面的这种模式时,往往根据具体的应用程序来选用不同的技术来实现
。看到上面的描述模式后,我们很容易就发现,可以用EJB来实现(EJB分两种,实体EJ
B和会话EJB)。
  我们知道,EJB提出来的目的是用于提供一种分布式组件系统的开发。如果我们的应
用程序是一个分布式的应用系统,那么毫无疑问,使用EJB来实现能大大减轻编程的工作
量。同时,通过使用EJB容器的一些高级特性,可以使应用程序更加可靠,扩展性也大大
加强。这样一来,开发人员就不必关心一些底层技术,比如事务处理,安全等各个方面
,而是把重点放在怎样实现业务逻辑上。但是我们应该注意,如果开发的应用不是分布
式的情况下,那么采用EJB有可能大大降低系统的性能。因为,EJB调用的开销很大。
  本文将探讨在不利用EJB技术的情况下如何来实现上面介绍的这个模式。
  下面以开发图书信息查询系统为例。
  1.实体类
  如前面讲到的,实体类的每个实例与表中一个记录对应。这样,实体类的属性应该
和表的每个字段一一对应。必须注意的是,实体类的实例是每个记录在内存中的对应,
因此,在程序中对实例的操作并不马上反应到数据库的记录中。
  在该类中,只是对数据的包装,因此,该类仅需要一些基本的方法,即setXX()和g
etXX()方法。
  下面是一个实体类,是对Book表的封装。
  class Book{
   protected int  ID;
   protected String Name;
   protected String ISBN;
   protected String Author;
   protected int  PublisherID;
   protecteddo
uble Price;
   protected int  Volume;
   public void setID(int iID);
   public int  getID();
   public void setName(String sName);
   public String getName();
   public void setISBN(String sISBN);
   public String getISBN();
   public void setAuthor(String sAuthor);
   public String getAuthor();
   public void setPublisherID(int iID);
   public int  getPublisherID();
   public void setPrice(double dPrice);
   publicdo
uble getPrice();
   public void setVolume(int iVolume);
   public int  getVolume();
   public Book(int iID, String sName, String sISBN, int iPublisherID,do
ub
le dPrice, int iVolume);
  };
  同样地可以对表Publisher进行封装。
  2.会话类
  会话类主要是对一个表进行处理。这些操作可以是在表中创建一条记录,删除一条
记录,更新一条记录和查找一条记录。这些操作的结果是将表中的记录和内存中的实体
类的实例对应起来,或将实例与表中的记录对应起来。
  我们可以看一下对Book表的封装。
  class BookTable{
   void Add(Book book);
   void Delete(Book book);
   void Update(Book book);
   Collection findbyID(int iID);
   Collection findbyXXXX(XX,XX);
   Collection findbyPulisherName(String sPublisherName);
  };
  上面的类的申明中,Add()用于将内存中的一个Book实例映射到数据库中。Delete(
)用于删除数据库中的某一个记录。Update()用于更新表中的一个记录。而findbyXXXX(
)则对应于SELECT语句。
  对于涉及到多个表操作时,可以有两种方式。一种是象BookTable一样,专门封装一
个类。另一个方法是,直接在BoolTable中写一个findbyPublisherName()。这个方法设
计成返回一个Book的集合。
  上面只是简单的介绍了怎样实现实体类和会话类。在具体的应用中,还要考虑到数
据库操作的一致性。下面就介绍一下事务处理的相关内容。
三、事务处理
  为了确保对数据操作的完整和一致,在程序设计时要充分考虑到事务处理方面的问
题。
  1.JDBC中怎样将多个SQL语句组合成一个事务。
  在JDBC中,打开一个连接对象Connection时,缺省是auto-commit模式,每个SQL语
句都被当作一个事务,即每次执行一个语句,都会自动的得到事务确认。为了能将多个
SQL语句组合成一个事务,要将auto-commit模式屏蔽掉。
  在auto-commit模式屏蔽掉之后,如果不调用commit()方法,SQL语句不会得到事务
确认。在最近一次commit()方法调用之后的所有SQL会在方法commit()调用时得到确认。

  下面的代码是一个示范:
  con.setAutoCommit(false);
  PreparedStatement updateSales=con.prepareStatement("UPDATE COFFES SET SA
LES=? WHERE COF_NAME LIKE ?");
  updateSales.setInt(1,50);
  updateSales.setString(2,"Colombian");
  updateSales.executeUpdate();
  PreparedStatement updateTotal=con.prepareStatement("UPDATE COFFEES SET T
OTAL =TOTAL+ ? WHERE COD_NAME LIKE ?");
  updateTotal.setInt(1,50);

  updateTotal.setString(2,"Colombian");
  updateTotal.executeUpdate();
  con.commit(0;
  con.setAutoCommit(true);
  2.J2EE中分布式事务处理
  在J2EE中,程序里可以使用JTA来调用底层的JTS(JAVA Transaction Service 提供
者服务)来处理分布式的事务处理。另外,如果使用EJB,可以通过在描述文件中指定t
ransaction的属性来实现。
  有关分布式事务处理的具体内容,请参见J2EE规范。
 
EJB Home Factory
客户端通过lookup定位home对象,但是对同一home的多次定位是多余的。
在应用程序的一次生命周期中,如何只使用一次定位呢?
***
通过JNDI来定位home接口是获取remote接口的第一步,为了获取remote接口,客户端必
需通过代码获取InitialContext,然后再调用实际的lookup进行定位。下面是演示代码

try {
//to get the initial context
Properties properties = new Properties();
// Get location of name service
properties.put(javax.naming.Context.PROVIDER_URl,
"some providers url");
// Get name of initial context factory properties.put(javax.naming.Con
text.INITIAL_CONTEXT_FACTORY, "some name service");
initContext = new InitialContext(properties);
}
catch (Exception e) { // Error getting the initial context ... }
try //to look up the home interface using the JNDI name {
Object homeObject = initContext.lookup("aHomeName");
myHome = (MyHome) javax.rmi.PortableRemoteObject.narrow(
homeObject, MyHome.class);
}
catch (Exception e) { // Error getting the home interface ... }
//get EJBObject stub
MyEJB anEJB = myHome.create();
代码显示了定位home是多么的复杂和它的重复性,问题是,对一个典型的应用程序来说
,要用到很多的home引用(每个EJB一个),这样为每个home写定位代码就是在重复代码

更糟糕的是,每次获取的home只用了一次(用来获取EJBObject stub),而每次JNDI定位
EJBHome都是非常昂贵的:
1)如果JNDI服务器位于另一台机器上,则需要一次网络调用。这种情况一般发生在集群
里,这时webServer/servlet并不在EJB Server上,而JNDI一般是EJB的一部分。
2)有可能需要IPC(Inter Process Communication),如果客户端与EJBServer在同一个b
ox中运行,而不在同一个虚拟机下,那么在定位home时就存在IPC耗费。
即使客户端(比如Servlet)与JNDI在同一个虚拟机上运行,为每个web请求进行JNDI定位
也是很影响性能的,因为EJB Home是不变的,可以被客户端一直重用。
一个好的方法是,使定位home的代码抽象化,并且可以在整个生命周期中重用。
因此,
将定位代码抽象为一个home factory,home接口在客户程序生命周期中得到缓存。
一个EJB home factory就是一个普通的实现为singleton的 java类,如图x.1所示,fac
tory封装了定位home的逻辑,并在其中对homes进行缓存,然后将缓存的home接口发送到
客户端。一个EJB home factory可以被任何应用程序重用,因为它并不包含类似getAco
untHome的特定的定位代码。实际上它定义了一个单一的lookUpHome方法,factory作为
封装和优化定位,可以在任何环境下使用,从applet到servlet,或者还可以在EJB之间
使用。
figure x.1
一个简单的factory实现的例子放在最后。使用EJB home factory很简单,客户端不再考
虑定位home和创建逻辑,只需要用下面的一条语句就可以了:
AccountHome anAccountHome = (AccountHome)EJBHomeFactory.getFactory().
lookUpHome(AccountHome.class);
注意,客户端传递的是.class,而不是JNDI名称,使用EJB home factory时,客户端甚
至不需要知道EJB 的JNDI名称。所要知道的就是home对象接口,但是在任何调用home对
象方法的地方都需要这个接口。
当客户端为一个特定的home对象调用EJB home factory时,都要先通过JNDI进行定位,
然后将home对象缓存到hashmap中,当响应不同的请求时,factory直接将缓存的对象输
出。
下面是一些实现的要求及实现的例子:
1)JNDI环境获取被放入到外部描述符。
不再是编写代码将JNDI factory 和URL字串放到properties对象中,然后传到InitialC
ontext构造器,而是将属性具体到客户端配置描述符,或者系统的运行属性(web.xml,
ejb-jar.xml for ejb’s, the –D flag for a standalone java client, etc)中,
这样,在运行期里,InitialContext可以自动在系统属性中找到这些属性,简化了fact
ory的实现,也提高了重用性。
2)有可能需要建立JNDI名称映射机制
后面的例子里假定ejb的JNDI名称是类的完整的名称(ie: com.xxx.xxxHome),如果这
些名称不可用,就需要在内部描述符中定义映射机制,在factory的构造器中,这些环境
获取应变为.class到JNDI 名称的绑定,并且存放在另一个hashmap中,另外,可以将JN
DI名称传到客户端,扩展lookUpHome(class) 方法为 lookUpHome(String jndiName, C
lass aClass);
此模式是一个简单而高效的方法,将复杂的home定位抽象为普通的,可重用的格式,通
过缓存home,减少了多余的home定位,极大的提高了性能。
EJB home factory提供了和home对象一致的接口,可以在任何环境下重用(applet, se
rvlet, standalone, even in-between EJB’s)。
Appendix X.X.1: Simple EJB Home Cache Factory Example
import javax.ejb.*;
import java.rmi.*;
import java.util.*;
import javax.naming.*;
/**
* EJB Home Factory, maintains a simple hashmap cache of EJBHomes
*/
public class EJBHomeFactory
{
private HashMap ejbHomes;
private static EJBHomeFactory aFactorySingleton;
Context ctx;
private EJBHomeFactory() throws NamingException
{
//Initialize context with System property Info
ctx = new InitialContext();
this.ejbHomes = new HashMap();
}
/*
* Returns the singleton instance of the EJBHomeFactory
**/
public static EJBHomeFactory getFactory() throws NamingException
{
if ( EJBHomeFactory.aFactorySingleton == null )
{
EJBHomeFactory.aFactorySingleton = new EJBHomeFactory();
}
return EJBHomeFactory.aFactorySingleton;
}
/**
* Lookup and cache an EJBHome object
**/
public EJBHome lookUpHome(Class homeClass) throws NamingException
{
EJBHome anEJBHome = (EJBHome) this.ejbHomes.get(homeClass);
if(anEJBHome == null)
{
anEJBHome = (EJBHome) javax.rmi.PortableRemoteObject.narrow (
ctx.lookup (homeClass.getName()), homeClass);
this.ejbHomes.put(homeClass, anEJBHome);
}
return anEJBHome;
}
}//EJBHomeFactory
 
在ejb中直接利用jdbc读取数据库记录
在一个后台使用关系数据库的ejb系统中,如果客户端只需要使用表格形式的用户界面来
显示数据,那么怎样才能高效的存取,表格化服务器端的数据呢?
在分布式计算中,一个最常用的用例就是为客户端显示服务器端的静态数据,这些数据
通常是只读的,在客户端很少要更新。举个例子:一个应用程序要显示大批量的数据到
客户端,这些数据是只读的,在html表格中显示可能如下:
---------------
Employee | Department
------------------------------
Adam Berman | Development
Ed Roman | Management
Clay Roach | Architecture
------------------------------
在服务器端,我们会将数据模型化为一个Employee实体Bean和一个Department实体Bean
.具体过程如下:在session Facade模式下调用getEmployees()方法。这需要先在home接
口上调用finder方法,返回所有的employee,对每个employee查找其对应的Department
Entity Bean.然后利用这两个实体Bean获取的数据,创建一个数值对象视图,session
bean将此数值对象的雇员/部门集合返回到客户端:
public class EmployeeProjectViewObject {
public String employeeName;
public String employeeTitle;
...
public String departmentName;
public String departmentLocation;
...
}
根据不同的ejb server和应用程序,这个过程会存在很多问题:
1)n+1次 Entity Bean的数据库调用问题
意思是:对BMP和某些CMP,从N个entity Beans中获取数据会需要n+1的数据库调用,对
一个好的CMP实现来说,应该允许批量加载,而一个开发者应知道这样会存在可怕的问题

n+1问题的产生过程:为了从N个entity bean中获取数据,首先必须调用finder方法(作
为一次数据库调用),在一个finder方法执行之后或者在一个商业方法调用之前,容器
为每个entity bean执行ejbLoad(),这就是说,每个entity bean都要调用ejbLoad()方
法(每个entity bean执行一次数据库调用),这样一个简单的数据库查询操作就需要n
+1次数据库调用。每一次的数据库调用都会在连接池中临时锁定数据库连接。通常分布
式系统的数据库一般都单独放在一台机器上,这样每次的数据库往返操作都会增加一次
网络调用。整个系统的速度就受到了影响。对我们这个例子来说,运行这个例子实际将
需要2n+1次数据库调用(1个查找finder,n个employee ejbLoad(),n个department ejb
Load()).
2)远程调用过多
如果要经过entity bean的远程接口,对n个employee &
department数据来说就需要3n次
远程调用
◆为每个employee的getValueObject有n次调用
◆................getDepartment ........
◆......department的getValueObject有n次调用
在获取每个数值对象集后,session bean将把这些数值对象绑定到EmployeeProjectVie
wObject上。
3)简单的联结操作(join operation)过于繁重。对这个例子来说,不管是BMP还是CMP,
都要实例化许多的entity bean,和处理entity bean之间的交互。设想一个稍微复杂一点
的情况,就是需要显示employee及相关的department,project &
company,这样就不是
仅仅增加几十行代码的问题,由于要增加数据库调用和远程调用,整个系统的速度将大
大的降低。
4)需要创建一个数值对象层,使用entity bean层进行数据库操作,需要实现Value Obj
ects,Subset Value Objects &
View Value Objects.这样增加了代码的复杂性降低了可
维护性。在我们的这个例子中,我们创建了数值对象视图,来封装从deployee bean &
department bean中获得的数据,并且把他们匹配发送到客户端。请阅读"Generic Attr
ibute Access"来进一步了解数值对象(Value Object)的使用。
当客户端只是浏览数据时,使用entity bean层的优点就不是很明显。使用本地接口和一
个好的CMP实现将明显得减少以上这些问题。但是BMP开发者就不会如此幸运。在BMP中,
只能通过使用entity bean缓存来减少这样的问题,而这只能用在单个EJB server部署上
,并且要求数据库的结构在ejb之外不能改变。否则的话,你只好忍受这些问题了。
还有既然客户端需要列表显示数据,这样将数据库中的数据转换为对象的优点也就体现
不出来了,因为还要将对象的数据在客户端列表化。
鉴于以上问题:
在BMP中,使用JDBC从关系数据库取出数据,使用RowSets将数据列表到客户端,在使用
Entity Bean来进行更新操作。
作为一个通常的笨拙的处理,你需要为客户端列出数据,然后你在session facade模式
下使用jdbc将比使用Entity Bean好的多。更重要的是,RowSets提供了一个清晰的和实
际的方法从JDBC记录集取出数据。然后直接列出到客户端,而不需要先将数据转化为数
值对象再将数据列出到客户端。
直接使用jdbc而不使用Entity Bean对许多开发者来说是不可思议的,自从Entity Bean
出现以来,人们就一直在为此而争论。毕竟,Entity Bean 很好的封装了数据和数据逻
辑,隐藏了持续管理的细节(比如:你不需要知道你所使用的数据库是什么),使整个系
统的商业概念模型化,使用了容器的许多特性,比如:连接池,并发性,事务等。如果
使用一个非面向对象的方法,似乎是一种退步。但是同任何其他的设计模式一样,有好
处也有坏处,这些将在后面讨论,不过我们先来看一下RowSets.
在ejb2.0中,RowSet 是一个接口,是javax.sql.ResultSet的子类。RowSet的特殊实现
允许你将ResultSet数据包装并排列显示到客户端,客户端可以直接操作RowSet记录集合
字段。jdbc2.0把这种实现称作CachedRowSet.CachedRowSet并不连接数据库,一旦它从
ResultSet中把数据复制过来,就可以断开与数据库的连接,此时,CachedRowSet就存放
了sql查询的结果集。
对我们这个例子,使用RowSet,我们可以将一张表里的所有数据一次性的存到一个对象
中,并且发送到客户端。下面的图形显示了RowSet方法与数值对象方法的区别
doc1.html
在客户端,从RowSet里取出的数据可以直接对应到表格的行和列。
使用JDBC和RowSet的优点:
1)RowSet为所有的查询操作提供通用的接口
2)简单的查询操作没有事务过载
3)利用缓存中的数据库
4)只返回你想要的数据
5)用户所要的数据只通过一次大的调用
缺点:
1)用户需要知道数据库表的字段名
2)商业逻辑与持续逻辑之间的紧密耦合
3)不是面向对象的
4)在编译期间不检查查询结果。
在数值对象中调用getXXX()而用RowSet在客户端需要调用getString("XXX")
5)有可能产生bug,可维护性差
最后,这个模式并不是说不要用Entity Bean,只说说当用户只需要临时列表显示数据时
,还有更高效的方法。在这个模式中,jdbc 和 RowSet用来进行列出数据操作而entity
bean责负责更新操作。特别注意:尽管RowSets也可以进行更新操作并且可以保证与数
据库的同步,但是在应用程序中永远都不要这么用!
尽管在客户端列表显示数据时,商业/数据概念的完整性以及和其他商业概念的联系显得
不是很重要,但是当进行更新操作时,这些概念就非常重要。Entity Bean封装了数据以
及对数据的"操作规则"。当更新Entity Bean的属性时,Entity Bean有可能需要进行有
效性验证并更新同一个应用程序中其他的Entity Bean。
举个例子:对一个应用程序中的Book和Chapter Entity Bean,当你修改Chapter Entit
y Bean章节标题时,Chapter将检验新的标题并且调用Book Bean让它进行修改,然后Bo
ok Bean有可能在调用其他的Entity Bean进行相应的修改操作。
从Session Facade通过jdbc/RowSets进行更新操作迫使开发者书写将商业逻辑和复杂的
数据逻辑混在一起的代码。所有的某个特殊的商业概念(business concepts)要求的规则
(rules),关联和验证都必须以更新记录和表的形式出现。
JDBC and RowSets for reading采用的是Session Facade模式,与Value Object 和 Ge
neric Attribute Access模式是不一致和不兼容的。Value Object 和 Generic Attrib
ute Access还可以进行更新操作。
 
VRGL你手上的资料到是真多啊,不错,颇有收获,谢谢。
 
据BEA公司称,电信行业使用的比较多。但是EJB应用水平极低,大部分仅限于
JSP/Servlet/JavaBean,所以J2EE大型项目,特别是成功的案例,好像还没有!
 
常常看到网上有讨论关于EJB效率的问题,最常见的就是关于entity bean效率低而
用stateless session bean来代替。就这个问题我们来分析一下。首先,EJB效率低
的一大原因就是通过rmi调用,rmi是一种java的远程方法调用技术,要通过TCP/IP,
比本地函数调用的开销要慢好多(最新的EJB规范提出了local interface的概念用以
弥补这一缺陷)。当然,entity bean效率低的还有更主要的原因,就是由于entity
bean的结构造成的。由于使用entity bean每查找一行数据要进行两次数据库操作
(一次是找出主键,另一次是通过主键找出数据),因此使数据库访问的效率大打折扣
。因此,有人提出使用stateless session bean访问数据库来代替entity bean。
就这种观点,我觉得有点搞形式主义的感觉,为了EJB而EJB了。EJB是一种体
系结构,遵循OO的设计模式,用以快速开发分布式的,结构灵活的,易于改变和扩
展业务逻辑的企业级应用,而以牺牲执行效率为其代价。在开发技术选型时,不该
首先就定下一定要用EJB+JSP然后在stateless session bean和entity bean里面进
行选择,而是先要分析系统是不是真的需要使用EJB。就如上面所说,如果是开发需
求多变的企业级应用应用系统,则应用EJB技术将大大简化系统的开发和维护成本;
如果系统需要有较高的执行效率,则JSP+JavaBean可能是更合适的选择。
总之,无论是什么技术,不是因为先进就一定要用,而是应该先利弊权衡这个
技术是不是适合需要开发系统,这样才能真真发挥出技术的优势。
 
个人感觉:大量使用entitybean和sessionbean是一个致命的问题。
 
收获不少!收藏!
 
看见了大家有这么好的见解:
D:/JBuilder4/jdk1.3/bin/javaw -classpath "D:/Inprise/AppServer/lib/navigator.jar;D:/Inprise/AppServer/lib/vbdev.jar;D:/Inprise/AppServer/lib/vbejb.jar;D:/Inprise/AppServer/lib/vbjdev.jar;D:/Inprise/AppServer/lib/vbjorb.jar;H:/Documents and Settings/Administrator/jbproject/tescro_5/classes;D:/Inprise/AppServer/lib/ias.jar;D:/Inprise/AppServer/lib/jmclient.jar;D:/Inprise/AppServer/lib/jmserver.jar;D:/Inprise/AppServer/lib/migration.jar;D:/Inprise/AppServer/lib/pjbean.jar;D:/Inprise/AppServer/lib/servlet.jar;D:/JBuilder4/jdk1.3/demo/jfc/Java2D/Java2Demo.jar;D:/JBuilder4/jdk1.3/jre/lib/i18n.jar;D:/JBuilder4/jdk1.3/jre/lib/jaws.jar;D:/JBuilder4/jdk1.3/jre/lib/rt.jar;D:/JBuilder4/jdk1.3/jre/lib/sunrsasign.jar;D:/JBuilder4/jdk1.3/lib/dt.jar;D:/JBuilder4/jdk1.3/lib/tools.jar" com.inprise.ejb.Container ejbcontainer "H:/Documents and Settings/Administrator/jbproject/tescro_5/quick.jar" -jts -jns -jss -jdb
Inprise EJB Container===================== server version : 4.1.1 server build date : Aug 18, 2000 java version : 1.3.0 java vendor : Sun Microsystems Inc. heap size : 1984 Kb java class path : D:/Inprise/AppServer/lib/navigator.jar : D:/Inprise/AppServer/lib/vbdev.jar : D:/Inprise/AppServer/lib/vbejb.jar : D:/Inprise/AppServer/lib/vbjdev.jar : D:/Inprise/AppServer/lib/vbjorb.jar : H:/Documents and Settings/Administrator/jbproject/tescro_5/classes : D:/Inprise/AppServer/lib/ias.jar : D:/Inprise/AppServer/lib/jmclient.jar : D:/Inprise/AppServer/lib/jmserver.jar : D:/Inprise/AppServer/lib/migration.jar : D:/Inprise/AppServer/lib/pjbean.jar : D:/Inprise/AppServer/lib/servlet.jar : D:/JBuilder4/jdk1.3/demo/jfc/Java2D/Java2Demo.jar : D:/JBuilder4/jdk1.3/jre/lib/i18n.jar : D:/JBuilder4/jdk1.3/jre/lib/jaws.jar : D:/JBuilder4/jdk1.3/jre/lib/rt.jar : D:/JBuilder4/jdk1.3/jre/lib/sunrsasign.jar : D:/JBuilder4/jdk1.3/lib/dt.jar : D:/JBuilder4/jdk1.3/lib/tools.jar=====================Initializing ORB........do
neInitializing JNS......do
neInitializing JTS....do
neInitializing JSS...Developer's License (no connection limit)Copyright (c) 1996-2000 Inprise Corporation. All rights reserved.License for JDataStore development only - not for redistributionRegistered to:
Inprise Application Server Development Licensee
Inprise Application Server Customer..do
neInitializing JDB......do
neInitializing EJBs.....java.lang.ClassNotFoundException: tescro_5.CabinHelperat java.net.URLClassLoader$1.run(URLClassLoader.java:200)at java.security.AccessController.doPrivileged(Native Method)at java.net.URLClassLoader.findClass(URLClassLoader.java:188)at java.lang.ClassLoader.loadClass(ClassLoader.java:297)at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:286)at java.lang.ClassLoader.loadClass(ClassLoader.java:253)at java.lang.ClassLoader.findSystemClass(ClassLoader.java:620)at com.inprise.ejb.util.ClassLoaderDriver$LocalClassLoader.loadClass(ClassLoaderDriver.java:472)at java.lang.ClassLoader.loadClass(ClassLoader.java:253)at com.inprise.ejb.Global.loadClass(Global.java:116)at com.inprise.ejb.EJBHome.<init>(EJBHome.java:75)at com.inprise.ejb.EntityHome.<init>(EntityHome.java:21)at com.inprise.ejb.Container.load(Container.java:858)at com.inprise.ejb.Container.run(Container.java:597).at com.inprise.ejb.Container.run(Container.java:1241)at com.inprise.ejb.Container.main(Container.java:1246)>>>> EJB LOG >>>>Could not deploy ejb-jar H:/Documents and Settings/Administrator/jbproject/tescro_5/quick.jarjava.lang.Error: Invalid helper class: tescro_5.CabinHelperat com.inprise.ejb.EJBHome.<init>(EJBHome.java:82)at com.inprise.ejb.EntityHome.<init>(EntityHome.java:21)at com.inprise.ejb.Container.load(Container.java:858)at com.inprise.ejb.Container.run(Container.java:597)at com.inprise.ejb.Container.run(Container.java:1241)Undoing effects of a partial deployment ...Jar name = H:/Documents and Settings/Administrator/jbproject/tescro_5/quick.jarThe home name is : Cabin.do
neContainer [ejbcontainer] is readyat com.inprise.ejb.Container.main(Container.java:1246)<<<< EJB LOG <<<<EJB Container Statistics
========================
TimeThu Oct 25 22:10:39 CST 2001
Memory (used)1122 Kb(max 1122 Kb)
Memory (total)2152 Kb(max 2152 Kb)
Memory (free)47.0%
------------------------
HomeCabin
Total in memory0
Total in use0
========================


运行客户端程序后是如下所一示:
D:/JBuilder4/jdk1.3/bin/javaw -classpath "H:/Documents and Settings/Administrator/jbproject/tescro_5/classes;D:/Inprise/AppServer/lib/ias.jar;D:/Inprise/AppServer/lib/jmclient.jar;D:/Inprise/AppServer/lib/jmserver.jar;D:/Inprise/AppServer/lib/migration.jar;D:/Inprise/AppServer/lib/navigator.jar;D:/Inprise/AppServer/lib/pjbean.jar;D:/Inprise/AppServer/lib/servlet.jar;D:/Inprise/AppServer/lib/vbdev.jar;D:/Inprise/AppServer/lib/vbejb.jar;D:/Inprise/AppServer/lib/vbjdev.jar;D:/Inprise/AppServer/lib/vbjorb.jar;D:/JBuilder4/jdk1.3/demo/jfc/Java2D/Java2Demo.jar;D:/JBuilder4/jdk1.3/jre/lib/i18n.jar;D:/JBuilder4/jdk1.3/jre/lib/jaws.jar;D:/JBuilder4/jdk1.3/jre/lib/rt.jar;D:/JBuilder4/jdk1.3/jre/lib/sunrsasign.jar;D:/JBuilder4/jdk1.3/lib/dt.jar;D:/JBuilder4/jdk1.3/lib/tools.jar" tescro_5.CabinClient
javax.naming.NameNotFoundException. Root exception is org.omg.CosNaming.NamingContextPackage.NotFoundat org.omg.CosNaming.NamingContextPackage.NotFoundHelper.read(NotFoundHelper.java:34)at org.omg.CosNaming.NamingContextPackage.NotFoundHelper.extract(NotFoundHelper.java:50)at org.omg.CosNaming._NamingContextStub.resolve(_NamingContextStub.java:161)at com.sun.jndi.cosnaming.CNCtx.callResolve(CNCtx.java:324)at com.sun.jndi.cosnaming.CNCtx.lookup(CNCtx.java:373)at com.sun.jndi.cosnaming.CNCtx.lookup(CNCtx.java:351)at javax.naming.InitialContext.lookup(InitialContext.java:350)at javax.naming.InitialContext.lookup(InitialContext.java:350)at tescro_5.CabinClient.<init>(CabinClient.java:19)at tescro_5.CabinClient.main(CabinClient.java:46)

请问这是什么问题!
 
to 小猪能否给一个你的地址好向你请教。
to vgrl能否给我一些材料呢
ps:dhyzf@163.com
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
D
回复
0
查看
2K
DelphiTeacher的专栏
D
后退
顶部