为何选择CMP体系结构?因为它强劲的性能  浏览次数: 390  时间:2004-04-19 
作者:Tyler Jewell 
上月,我谈到了CMP实体 EJB的强大功能,并提供了大量的适用场合,这些场合下适合于利用CMP模型来开发使用JDBC和JDO的无状态会话EJB。本月,我们将讨论为什么要在实体EJB中使用CMP体系结构而不是BMP体系结构。使用BMP实体 EJB的理由首先,我们谈谈在实体 EJB系统中适合于使用BMP的场合。使用BMP而不使用CMP的最大理由是因为有些工作通过CMP完成不了:·           通过存储过程存取的字段:如果你所工作的企业通过存储过程控制数据存取,CMP引擎将不知道如何与适当的存储过程进行交互。实体 EJB生命周期是非常精确的,任何访问数据库的存储过程都不可能遵循这一生命周期。还有,即使存储过程遵循实体EJB生命周期,在生命周期过程中的不同点,也不会有判断存储过程调用哪个CMP容器的标准方式。·           通过可选方法访问持久性存储器:WebLogic Server的CMP引擎需要使用JDBC驱动程序来访问持久性存储器。如果你想用另一种访问技术,比如JDO或是J2EE CA 适配器,就必须用到BMP模型。·           Bean模型需要多个存储器的数据:WebLogic Server的CMP引擎仅能读取单个表的数据。而WebLogic Server  7.0将会支持多表CMP存取,但如果在Bean模型中的数据来自多个数据库,该怎么办了?尽管出于很多重要性能方面的考虑,不使用单个实体EJB表示来自多个存储器的数据,但有些场合是需要用到的,特别是当你试图用一个新的实现去整合遗留系统时。在这些场合,应该使用BMP bean。·           数据库需要非标准SQL:数据库通过添加专有的扩展名来区分开自己,这些专有的扩展名启用了更好的性能和更健壮的功能。举个例子,大部分数据库提供自动生成主键的技术;另一些则提供专门的方法来完成数据库级的优化锁定。要利用这些特性,提交到数据库的SQL通常必须用数据库供应商定义的专有扩展来定制。CMP引擎通过支持广泛的自定义扩展来区分开自己。WebLogic Server 6.1支持大多数主键生成技术和Oracle的序列化SQL扩展,但如果数据库需要进一步优化的SQL,那就不得不用BMP来代替了。为什么选择CMP?如果正在使用BMP EJB,恰好您的程序环境又与上述情况相符,那么BMP实体EJB将不能很好的执行。当使用一个CMP引擎或是带有JDBC的无状态会话EJB时,如果选择使用BMP实体EJB,那么将会带来不必要的性能影响。一个BMP实体EJB不能在没有容器管理、服务器管理和(有时)不必要的生命周期迁移等开销的情况下使用。以下是使用BMP的情况:1.在系统的业务对象模型中利用表示持久性数据2.利用EJB部署模型,允许通过修改XML做出行为的改变,而非代码的改变。3.数据访问属于本文第一节列出的场景之一。但是,如果你想要完成的任务不适合其中任一场景,并且对于CMP容器引擎来说,其功能足以完成所需要的数据访问,应该尽量使用CMP。使用CMP有很多具体原因:·           BMP 实体 EJB不能利用服务器内锁定模型: 这包括悲观式和乐观式服务器内锁定模型。支持乐观式服务器内锁定模型的容器非常少,但它功能很强大。乐观锁定延迟了尝试锁住数据库底层数据,直到事务开始提交。要做到这一点很困难,因为容器需要非常智能化,可以意识到当事务开始时和容器给数据上锁时任何数据的修改。假如数据在另外一个进程访问时被修改,就会引发一个冲突,那么容器就通过回滚事务或是覆盖数据来解决这个问题。支持乐观锁定的容器提供了更加可扩展的实现,因为数据很少会被频繁地锁住,应用服务器也不会把系统周期浪费在访问锁住的数据上。通过支持悲观锁定和乐观锁定模型的容器,bean开发人员可以从处理多请求事务问题、冲突解决和专用于生成这些锁定场景的SQL语句中解放出来。但是BMP 实体EJBs没有实现这些策略的容器,因为它需要与底层持久存储进行交互。·           BMP实体EJB不支持EJB-QL:EJB-QL查询语言常用于定义方法find()和ejbSelect()。它允许开发人员快速配置实体EJB行为而不用开发复杂的JDBC和SQL代码。包括WebLogic在内的供应商可以对EJB-QL进行加强,这样就能不断地创建较为复杂的查询。通过完成这些之后,对于优化的存储过程需求就会减少,而业务逻辑也会转移到应用服务器层的更底端。另外,EJB-QL减少了实体EJB里的代码数量,这使EJB变得更稳定,容易维护和开发。BMP实体EJB需要手工执行find()方法。鉴于上述种种理由,我们应当尽量避免采用BMP实体EJB。·           BMP 实体 EJB不支持任何关系:也许你的数据与其他数据有关系。这是经常碰到的。如果你的数据之间有这种关系,那么在内存中的对象模型也会存在这种关系。手工建立这些关系是一项非常有挑战性的工作。它们之间可能会存在一对一和一对多的约束。很多系统并不能很好地处理这种难于实现的关系。举个例子,如果你有一个被永久存储的一对多的对象关系,你有时会加载这些父对象,但是这个父对象含有10000个子对象,每次都会连同子对象加载,而在常规的运行中我们并不需要这些子对象,此时的系统就会超负荷的工作,我们要想办法避免这些现象发生。在持久存储中,BMP实体 EJB容器由于需要对底层关系管理进行访问,所以并不支持关系。在关系型数据库的情况下,容器需要访问主键和外键字段来管理这些关系。使用BMP,所有持久存储访问由Bean自己管理,这样Bean就需要手工地管理这些关系。由于BMP关系不规则,实现就很困难,所以构建这种难于实现的系统是很危险的。另外,WebLogic服务器的CMP实现提供了关系的积极和消极加载,这在使用BMP实现时是不可能做到的。·             BMP 无法避免n+1 问题: 利用 EJB 1.1 的CMP引擎所碰到的问题之一是n+1问题。这个问题是由容器引起的,因为在父-子关系中容器需要n+1个数据库查询和网络调用来加载实体EJB。例如,如果您有一个Order实体EJB,在一对多关系中具有1,000个LineItem子实体EJB,EJB 1.1 CMP引擎将需要1,001个数据库查询来加载所有EJB。这真是太不可思议了,因为很有可能所有数据都只存储在两个表中。·             通过要求关系中的实体EJB使用本地接口,EJB 2.0为CMP引擎解决了这一问题。容器能够保证关系中的实体EJB存在于同一虚拟机器中,并且如果供应商需要关系存在于同一数据库中的话,CMP引擎能够连续地将n+1场景优化为一个1+1数据库命中场景。对于BMP容器来说,就不是这种情形了。由于容器不创建查询,没有任何标准的方式来“聚合”所有这些信息,从而一次传递所有子数据。BMP引擎将一直迭代每一子数据,迫使n+1保持下去。然而,如果你需要在远程接口上操作关系的话,那么这是在关系中使用BMP的一个理由。如果本地接口限制无法遵循的话,也可以使用BMP。·           BMP无法完成级连删除:对于关系中的EJB,CMP容器能够执行级连删除。这意味着如果一个父对象被销毁时,那么关系中的子对象也会自动销毁。当有一整行数据被删除时,级连删除可以通过手工在同一时间删除每个EJB来完成,也可以通过使用专用的数据库参照完整性机制来完成,后一种方法在删除某行时,自动删除与外键相关联的所有数据。出于性能方面的考虑,后者是首选的方法。因为BMP实体EJB容器不访问底层数据存储,所以在删除大量数据方面不能利用优化的数据库技术。这会对性能和可移植性会产生巨大的影响。BMP容器无法自动生成主键和表:WebLogic Server容器实现的一个特点是能够创建表、建立关系和自动生成数据库主键。因为EJB到数据库的耗时映射不常发生,容器又可以自动地创建合适的表和关系,所以开发周期大大的缩短。另外,大部份数据库都可以自动地生成惟一主键值。如果容器能够查询数据库并把信息传送到服务器,实体EJB就能利用数据库生成的主键值。而对于BMP容器来说,创建数据库表或是建立关系无论用什么方法都是不能实现的。另外主键生成技术是对于所使用的数据库来说都是专有的,因而无法使用BMP实体EJB通过可移植性来完成。结束语CMP实体EJB 在生产系统里没有被充分利用,而有时BMP实现又常常被滥用。当你下一次实施项目时,考虑到性能方面和减少开发成本方面的优势,建议使用高质量的CMP容器,而不是使用BMP体系结构开发数据访问逻辑。相信我,这样做的结果会让你很满意的。关于作者Tyler Jewell是BEA技术推广部门的主管,并且是Mastering Enterprise JavaBeans 2.0和Professional Java Server Programming (J2EE 1.3) 这两本书的合著者。他在Web上编写了有关J2EE 和Web 服务这两个主题的大量文章。