本文中我不打算解释EJB的复杂性。即将推出的EJB 3规范专门针对目标和开发模型,使得它更容易;该规范还提供依赖注入以及在实体bean容器之外的更容易的测试。相反,本文的目标在于提供BEA WebLogic Server 8.1和9.0中可用的高级选项的深度分析,使开发人员改善CMP bean的性能——在很多情况下可极大地改善。该主题很宽泛,不可能在一篇文章中一一涉及;因此,我只重点讨论CMP实体bean的并发以及长期缓存策略。我还简要说明了最新版本BEA WebLogic Server 9.0中的改进。
并发策略
J2EE开发人员知道EJB容器维护了一个实体bean缓存或者池,通常可在部署描述符中配置。令人惊奇的是,相当多的J2EE开发人员不知道这并不意味着一旦J2EE服务器从数据库中加载一个特定的bean实例,它就不再去数据库中寻找该实例,因为该实例已经保存在缓存池中了。相反,默认情况下J2EE服务器执行ejbLoad()在每次事务的开始从数据库中同步该实例的状态。基本上,CMP bean每运行一次(即使该bean在前一个事务中已经被加载),服务器就执行一次SQL select语句来刷新它。只有在一个事务中操作多个实体bean实例时,服务器才会缓存它们。
显然,在每次事务中都重新从数据库中加载状态会造成很大的性能影响!这个默认行为很容易理解:如果数据库被多个进程共享,并且每个进程都可以改变数据库中持久对象的状态,那么这将是最安全的方法。但是可以通过告诉J2EE服务器保留事务间实体bean的缓存实例,从而避免大部分时间里从数据库中刷新数据来略微改善这种情况。为了解决这个问题并生成一个最优的解决方案,首先我将讨论BEA WebLogic Server中可用的不同的并发策略。
对于EJB开发人员来说很重要的一点是要知道实体bean中可用的不同并发策略。令人惊奇的是,有的开发人员甚至不知道并发选项的存在。那么适用于实体bean的并发策略是什么呢?EJB容器是一个高度多线程的应用程序,同时响应来自多个客户端的请求,这些请求通常会访问同一资源,比如数据表中的一行。因此,EJB容器应该管理对实体bean实例的并发访问;更加技术性地讲,并发策略决定了容器如何以及何时将实体bean的每个实例与底层数据库同步。
目前WebLogic Server中有四种可用的并发策略:排他、数据库、乐观和只读。默认情况下,从7.0版本开始,WebLogic Server就使用的是数据库并发。上面四种策略按性能从低到高依次排列。我将讨论每种策略的优缺点。
排他性并发
排他性并发意味着容器最多为每个主要键值创建一个实体bean实例(比如,表中的一行映射到容器中的一个EJB实例)。对指定实例的访问是串行的,并且请求是按照顺序逐个执行的。这种策略有一些严重的问题。首先,性能由于多个客户端对bean的串行访问受到明显影响,并且您不能再考虑应用程序的伸缩性。其次,EJB的单个实例(以及容器持有的关联锁)对于一个JVM(一个服务器实例)来说是本地的,不能在集群中工作。该策略只是用于后向兼容(早期版本的WebLogic Server默认使用它),应该尽量不用。