在APUSIC J2EE应用服务器中优化ENTITY BEAN - 深入J2EE技术 - 付毅

(这条文章已经被阅读了 33 次) 时间:2001-08-14 20:38:58 来源:付毅 (mytuotuo) 原创-IT

ENTITY BEAN 在应用和应用的设计阶段代表持久性商业对象,在对象模型中,简单的java对象通常可直接表示出,但并不包括商业对象需要的事务持久性管理功能,ENTITY BEAN 不仅可以代表相同的对象模型,而且在隐藏bean背后所有的复杂性和容器服务的同时,封装了持久性机制。在开发基于面向对象的J2EE的项目中,我们可能会用到大量的ENTITY BEAN,以下是在用APUSIC开发EJB 应用时的一些优化技巧:
一)尽可能的使用CMP模型
APUSIC 的CMP模型不仅可以使你简化了大量的代码,而且可以利用容器提供的优化功能和容器产生的数据库访问代码,根据内部测试结果,APUSIC在CMP的优化方面,要超出国外同类产品许多。具体测试结果,可参见http://www.apusic.com/docs/products/cpdt/6851087292.htm
二)最小化ejbStore的数据库访问
当用CMP时,BEAN不可能控制ejbStore,所有的优化是容器管理的,容器在CMP优化方面的差异成为区分容器快慢的一个重要因素。当你用BMP部署一个BEAN时,为数据缓冲设置一个dirty变量很有用,缓冲的任何改变都必须设置dirty标志,以便由ejbStore检查。如果dirty标志没有被设置,说明缓冲没有改变,ejbStore将跳过所有宝贵的数据库调用,这个技巧在经常查询但很少更新的应用中特别有用,许多应用的大部分工作都是进行表的查询。
用这个技巧有一些限制,由于dirty标志是为数据库访问设置的,所以它应适合与BMP而不是CMP,把它设在BMP或DAO(数据库访问对象,把BMP中所有关于持久性的代码写到一个辅助类,这种辅助类成为DAO)中,由于商业方法并不调用DAO,所以DAO并不是设置dirty标志的地方,只有把它放在BMP实现类中。这就使BMP代码更复杂。
按道理说,EJB的书写者不应该处理象管理缓冲这样系统级事务,但EJB1.1中的BMP并没有提供可选的优化方案,因此必须手工设置dirty标志.
在APUSIC中你可在apusic-ejb-jar.xml文件中设置如下选项:
isModified
这样,你可在BEAN中实现一个名为isModified的方法,返回dirty的状态,同时你需要一个设置dirty的方法,当实例变量发生变化时,及时设置。具体代码实现参见http://www.apusic.com/product/download.htm中APUSIC1.0版本中APUSIC_HOME\SAMPLES\EB下的ENTITY BEAN .
三)避免死锁
应用程序不能直接调用ejbStore,而是有容器决定什么时候调用,通常是事务的结束.
如果多个ENTITY BEAN 或实体参与一个事务中,ejbStore 调用的顺序就不一定.这也意味着用户不能控制访问(锁定)代表这些实体的数据库记录的顺序.当有多个表/行参与时,混合锁定顺序往往造成死锁.
在APUSIC应用服务器(包括在其它应用服务器)测试过程中,有时会出现上述死锁情况,作为可适用的规则,应假设容器进行数据库的调用顺序应和BEAN的事务方法第一次被调用的顺序一致.比如,假设ENTITY BEAN EB1有一个事务方法M1,ENTITY BEAN EB2有一个事务方法M2,如果在同一事务中EB1.m1在EB2.m2之前调用,可以认为EB1.ejbLoad 在EB2.ejbLoad 之前调用,EB1.ejbStore 在EB2.ejbStore 之前调用,这就意味着EB1代表的实体先于EB2锁定,为避免死锁,应保证整个应用的每一个事务EB1总是先于EB2调用.
四)缓存从lookup 和 find方法返回的引用
引用缓存对实体BEAN和SESSION BEAN 都有用。通过JNDI查找EJB资源,如数据库,BEAN引用,环境变量(environment entry)是相当耗费资源,用以下方法可避免重复查找:
(1)把这些引用定义为实例变量
(2)在setEntityContext (setSessionContext )中进行查找。
setEntityContext 只有在实例一个BEAN 时被调用一次,所以在这里查找所有你想要的引用是一个不错的办法,不要在其它方法中查找资源,特别是数据库访问方法如 ejbLoad 和ejbStore(甚至是查找数据库) ,这些方法会经常被调用,因此会在查找过程中浪费大量时间。
过多的find方法调用也会,影响BEAN的效率,由FIND方法调用返回的引用可能并不适合在setEntityContext中进行缓存,但应尽可能在其它地方缓存。如果引用只对当前实体有效,那么应在代表实体的实例被重新激活之前清除引用,这个过程可以在ejbActivate 中实现。