| 本文探讨了如何在使用BEA WebLogic Workshop 8.1来开发应用程序并将其部署到BEA WebLogic Server 8.1 的情况下,将MySQL用作数据库引擎。使用一个原型的J2EE架构,我从诸如选择正确的MySQL 版本、设置服务器以及进行开发调整等各个方面来评价使用MySQL的影响。
本文探讨了如何在使用BEA WebLogic Workshop 8.1来开发应用程序并将其部署到BEA WebLogic Server 8.1 的情况下,将MySQL用作数据库引擎。使用一个原型的J2EE架构,我从诸如选择正确的MySQL 版本、设置服务器以及进行开发调优等各个方面来评价使用MySQL的影响。这里提供的信息不仅增强了读者对于所使用的工具和技术的理解,而且节省了大量的时间。即使是使用不同数据库技术的读者也会发现该信息和资料非常有用。
上个月(WLDJ,Vol. 3,issue 4),我们讨论了如何选择正确的MySQL版本,并描述了为支持诸如Java Database Connectivity (JDBC)和Java Message Service (JMS)等关键J2EE技术而对WebLogic Domain Configuration的各种改变。本月,我将描述各种变化、调整和修改以支持Enterprise JavaBeans (EJBs),它是J2EE和Java Transaction API (JTA)的核心组件模型。正如第一部分那样,选择的开发工具是WebLogic Workshop 8.1 ,而且应用程序部署到WebLogic Server 8.1。
子系统架构
一个J2EE应用程序包含许多子系统或模块。原型应用程序包含下列的子系统:UtilProject、DomainProject、 AgentProject、 TestProject和SEMAppWeb 。这些子系统以及它们之间的相互依赖在图1中给出描述。UtilProject包含通用工具类。DomainProject包含容器管理持久性(CMP) EntityBeans以及一个Session Facade Stateless Session Bean (SLSB)。AgentProject包含一个SLSB,用于将消息排入一个队列中而进行异步处理,以及一个Message-Driven Bean (MDB),用于处理消息。TestProject汇集所有其他项目中的测试。 SEMAppWeb项目是默认的 web项目。
在更进一步之前,你必须完成下面的步骤:
- 创建一个BEA WebLogic Workshop 应用程序(如SEMApp)。
- 选择SEMDomain作为服务器。
- 向库中添加junit.jar。
- 向SEMApp 中导入一个名为UtilProject的Java 项目。
- 向SEMApp 中导入一个名为DomainProject 的EJB项目。
- 向SEMApp 中导入一个名为AgentProject的EJB项目。
- 向SEMApp 中导入一个名为TestProject 的Java项目。
- 根据项目依赖关系,将构建顺序改变如下:UtilProject、 DomainProject、AgentProject、 SEMAppWeb、 TestProject。
- 构建所有项目。
- 启动WebLogic Server。
下一部分从对Enterprise JavaBeans 的高层概述开始,着重探讨将它们用于MySQL时所出现的问题。
Enterprise JavaBeans (EJB)
Enterprise JavaBeans是J2EE的核心组件模型。有三种类型的EJB:Session Bean、 Entity Bean、和Message-Driven Bean。 Entity Bean专门用于与数据库交互。有两种类型的Entity Bean: bean管理 (BMP)的 Entity Bean和容器管理 (CMP)的 Entity Bean 。使用BMP时,程序员编写所有JDBC代码,并控制该代码。使用CMP时,程序员在扩展标记语言(XML)中显式指定持久性。EJB容器通过生成必要的JDBC代码来负责提供持久性。原型J2EE蓝图架构使用带有CMP的Entity Bean。
下面的部分讨论使用MySQL和带有CMP的Entity Bean时出现的问题。 一个问题是自动主键生成。另一个问题是可延迟约束。原型示例应用程序包含了许多CMP实体bean来说明这些问题。图2中给出了一个CMP实体bean及其相互关系的类图。
自动主键生成
BEA WebLogic Server支持两种自动主键生成方法。 第一种方法,称为NamedSequenceTable 策略,使用一个顺序表。这种方法是通用的,适用于包括MySQL在内的大多数数据库。举个例子,对于Person 表,会创建一个Person_Seq表来进行主键生成。Person_Seq 表有一个名为Sequence 的列。在序列开始处(通常是0)向Person_Seq表中插入一行。请参考所提供的源码示例中的sem.sql 。为每个实体的自动主键生成插入下面的EJBGen 标记:
*
* @ejbgen:automatic-key-generation
* cache-size="10"
* name="Person_Seq"
* type="NamedSequenceTable"
*
参考示例源代码(源代码可在www.sys-con.com/weblogic/sourcec.cfm处找到)中的用于PersonBean.ejb的源代码。
第二种方法利用本地DBMS支持。例如,Oracle具有可被用于进行自动主键生成的序列,而Microsoft SQLServer具有用于自动主键生成的标识列。BEA WebLogic Server仅支持Oracle 和 Microsoft SQLServer数据库的本地DBMS特性。
建议在整个项目中使用单一的、自动的主键生成技术。由于NamedSequenceTable 策略是得到正式支持的,所以推荐采用该策略。有关自动主键生成支持的更多信息,请访问http://e-docs.bea.com/wls/docs81/ejb/entity.html#115=399。
可延迟约束
Oracle 和DB2等数据库支持一种称为可延迟约束的特性。如果使用一个可延迟约束,该约束,比如一个外键,在插入或更新期间不会立即被检查。该约束将在晚些时候的委派时间被检查。这一能力使得WebLogic Server CMP 引擎有相当大的时间余地来排序SQL语句,从而实现最大效率和最高性能。但是,MySQL不支持可延迟约束。因此,默认的CMP行为将引起外键冲突,因为约束总是立即被检查。例如,Person 和PersonStatus 实体之间的关系证明了这一问题。一种可能的解决方法是关闭数据库操作的排序。插入下面的EJBGen标记来关闭数据库操作的排序:
* @ejbgen:entity
* ...
* order-database-operations="false"
然而,该标记无论如何是不起作用的。默认情况下会启用语句的批处理。如果启用语句的批处理,那么数据库操作的排序将自动地被启用。因此,要同时关闭操作的批处理和数据库操作的排序。插入下面的EJBGen标记来关闭数据库操作的排序和语句的批处理:
* @ejbgen:entity
* ...
* order-database-operations="false"
* enable-batch-operations="false"
请参考代码示例中PersonBean.ejb 的源代码。建议将该项目中的所有实体bean的排序数据库操作和启用批处理操作指定为“false”。
选择日期和时间列的类型
日期和时间以多种不同的方式使用在一个应用程序中。一个使用日期和时间的具体例子是,维持如创建日期和更新日期等审计信息。创建日期记录着该行插入的日期和时间。更新日期则记录着该行修改的日期和时间。有许多不同的方法来处理和解决该难题。一种方法是以程序方式来保持和更新代码中的所有信息。该方法的好处是程序员可以完全控制代码。该方法的缺点是代码必须被编写、测试、调试和维护。
另一种方法是利用特定于数据库的特性来自动地插入或更新信息。这种方法的优点是程序员不必编写、测试、调试和维护代码。该方法的缺点是程序员受到数据库中可用工具的限制。一种自动插入和更新日期的方法是利用数据库触发器。遗憾的是,尽管MySQL将来的一个主版本将支持该方法,但目前的版本不支持该方法。但是,MySQL仍然可以用于自动插入和更新日期和时间类型。考虑MySQL中可用的日期和时间列类型: DATE、TIME、DATETIME、TIMESTAMP和 YEAR。为了审计的目的,由于日期和时间都很重要,仅DATETIME 和TIMESTAMP是有意义的。
考虑BUYER 表的DDL。CREATE_DATE和UPDATE_DATE列都是DATETIME列类型。程序员负责维护 CREATE_DATE和UPDATE_DATE。笔者建议的设置创建日期的位置是在ejbCreate()方法中。请参考该示例中所包含的BuyerBean.ejb 。笔者建议的设置更新日期的位置是在session facade update 方法中。请参考该示例中的DomainFacadeBean.ejb中的updateBuyer() 方法。
考虑PERSON 表的DDL。CREATE_DATE和UPDATE_DATE列都是TIMESTAMP列类型。 更新PERSON 表中的一行将自动更新CREATE_DATE 列,而UPDATE_DATE列保持不变。这一结果不是所期望的。至少有两种可能的方法来获得所期望的结果。一种是如ADDRESS 表中所描述的那样改变CREATE_DATE和UPDATE_DATE列的顺序。 另一种方法是如PRODUCT 表中所描述的那样将CREATE_DATE的列类型改变为DATETIME 类型,同时以程序方式设置CREATE_DATE。
考虑SELLER 表的DDL。CREATE_DATE 和UPDATE_DATE列都是 TIMESTAMP列类型。然而,与PERSON表相比较,CREATE_DATE和 UPDATE_DATE的顺序与DDL中列出的是颠倒的。 UPDATE_DATE列在 CREATE_DATE 列之前被列出和创建。在SELLER表中更新一行将自动更新UPDATE_DATE 列,而CREATE_DATE 列原封未动。这便是预期的结果。
考虑CREDIT_CARD 表中的DDL。CREATE_DATE列类型是DATETIME,而UPDATE_DATE 列类型是TIMESTAMP。以程序方式设置 CREATE_DATE 列。当表中的行被更新时, MySQL自动更新 UPDATE_DATE 列。这是预期的结果。建议在ejbCreate()方法中设置创建日期。请参考源代码示例中包含的CreditCardBean.ejb的代码。
请谨记下面关于TIMESTAMP 列类型的规则:
- 如果在任何TIMESTAMP 列中插入了NULL,则列值自动设置为当前日期和时间。
- 当仅为该行中的第一个TIMESTAMP 创建或更新,并且该列中未插入值时,该列值被自动设置为当前的日期和时间。
- 插入一个显式的日期和时间值将显式地消除时间戳。
建议仔细地选择一种策略并在整个项目中实现它。
其他建议
一个建议是,应始终使用对象类型而不是原始类型。例如,使用java.lang.Integer而不使用int。java.lang.Integer 的默认值为null,而int的默认值为0。如果存在一个可为null的外键约束,则当使用默认值0将与该约束相冲突,因为在外部表中没有这样的匹配行。
许多特性可被设置来允许输出更多的信息,以便辅助调试和监控。weblogic.ejb20.cmp.rdbms.codegen.verbose便是这样的一个特性。将该特性值设为true能显示JDBC语句,以及将参数绑定到这些语句。
JTA 域配置变更
JTA是一个应用编程接口 (API) ,用于在不同资源间协调分布式事务。比如,使用JTA,在一个单一全局事务中就可以发送或接收一个JMS消息并且可以通过JDBC将数据提交给数据库。在本例中,一个资源是JMS服务器,另一个资源是RDBMS。该分布式事务跨越了JMS服务器和RDMBS。为了支持分布式事务,诸如数据库服务器或JMS服务器等资源必须支持工业标准的X/Open XA 协议。访问该资源的驱动程序也必须支持XA。
例如,考虑一下AgentFacadeBean's enqueuePerson()方法。该方法不仅写入数据库,而且将一个消息排入队列。JMS和RDBMS都需要支持XA。
如果JMS资源不支持XA,那么使用资源引用来获取连接工厂时会导致出错。出错消息将通知你“两阶段提交不可用”。对于SEMDomain而言,设置连接工厂的属性以支持XA。
在JMS连接工厂上支持XA
下面的步骤描述了如何在JMS连接工厂上支持XA。
- 确保BEA WebLogic Server正在运行。
- 启动WebLogic Server Console。
- 登录到该Console。
- 选择Services / JMS / Connection Factories.
- 选择 semJMSConnectionFactory。
- 选择Transactions标签。
- 选中XA Connection Factory Enabled 复选框。
JDBC数据源不支持XA。MySQL以及MySQL的JDBC驱动也都不支持XA。执行AgentFacadeBean's enqueuePerson()方法将抛出异常TransactionRolledbackException,其内容为“JDBC驱动程序不支持XA,因此不能参与两阶段提交。若要参与两阶段提交,必须在相应的JDBCTxDataSource上将EnableTwoPhaseCommit属性设置为true”。
BEA WebLogic Server允许处理分布式事务,即使至多有一个资源不支持XA。它具有为不支持XA的资源而模拟XA的功能。为了模拟XA并且允许MySQL 参与到两阶段委派中,应修改访问MySQL 的数据源配置以便模拟XA。
模拟 XA
下面的步骤描述了如何改变数据源的配置来模拟XA。
1. 确保BEA WebLogic Server正在运行。
2. 启动WebLogic Server Console。
3. 登录到该Console。
4. 选择Services / JDBC / Data Sources。
5. 选择一个JDBC数据源( Data Source )(如semJDBCDataSource)。
6. 点击Show显示高级选项(Advanced Options)。
7. 选中Emulate Two-Phase Commit for non-XA driver 检查框。
事务和重新交付
在示例应用程序中,ProcessPersonBean Message-Driven Bean (MDB)监听队列并处理离开队列的事务。ProcessPersonBean与Container Managed Transaction Demarcation (CMTD) 一起配置,将事务属性设置为Required。onMessage()方法在一个容器事务中执行。调用MessageDrivenContext的setRollbackOnly()方法将回滚事务。当onMessage()抛出一个运行时异常时,WebLogic Server也会回滚事务。根据JMS规范,从onMessage()方法扔出一个运行时异常被视为出现一个编程错误。
如果事务被回滚, WebLogic Server 将重新交付消息。默认的重新交付计数值为-1,意思是消息被重新交付的次数没有限制。只要事务被回滚,没有限制将导致BEA WebLogic Server 一遍又一遍持续不断地重新处理消息。WebLogic Server server 会陷入一个无限循环。为了防止WebLogic Server一遍一遍无休止地处理同一个消息,重新交付计数值可以被修改。 对于SEMDomain而言,将重新交付计数值配置为0或更高值即可。根据目的地是常规节点(如非分布式的)还是分布式节点,重新交付计数值的修改是不同的。为非分布式目的地修改重新交付计数的一个方法是,在目的地自身上修改重新交付计数。为分布式目的地修改重新交付计数的一个方法是,修改与分布式目的地相对应的JMS模版上的重新交付计数。
设置重新交付计数值
下面的步骤描述了如何改变重新交付计数值或PersonQueue。
- 确保WebLogic 正在运行。
- 启动WebLogic Server Console。
- 登录到该Console。
- 选择Services / JMS / Templates。
- 选择PersonQueue。
- 选择Configuration 标签。
- 选择Redelivery 子标签。
- 改变Redelivery Limit 值为 3。
运行和验证
为了验证所有的一切均已适当配置且应用程序已经部署,需要运行MasterTest 类。MasterTest 汇集了所有的JUnit测试。复制sample-build.properties到build.properties然后改变属性值来与环境相匹配。通过调用ant来运行MasterTest : ant invokeMasterTest。
结束语
本文讨论了在使用带有容器管理持久性的Entity Bean和MySQL的过程中出现诸如主键生成和可延迟约束等问题。我们探讨了为了支持Java Transaction API 而对WebLogic Domain Configuration的更改。理解了用EJB、JMS、JDBC和JTA等各种不同J2EE技术来使用MySQL 时的影响,这种影响对于成功的项目实现是必须的。如前面所描述的,MySQL、BEA WebLogic Workshop以及BEA WebLogic Server 构成了一个强大的组合来构建、设计和部署任务关键的应用程序。我想感谢Steve Ditlinger、Roshni Malani和Sarah Woo,他们审阅了这篇文章,提供了很有价值的反馈意见。
参考文献:
· Malani,Prakash。“考虑 MySQL?继续阅读......,第 I部分”。BEA WebLogic 开发者杂志,第3卷,第4期
· 讨论这篇文章和提问问题请从这儿开始: =ttp://groups.yahoo.com/group/bartssandbox。需要免费会员资格。
· 主要的 MySQL Web 站点: http://www.mysql.com/=/a>
· MySQL 文章的入门点: www.mysql.com/documentation/index.html
· www.=reillynet.com/lpt/wlg/3946
· 与EJBGen相关的一切: www.b=ust.com/cedric/ejbgen
· 关于JMS事务和重新交付选项的详细信息: www.javaworld.com/javaworld/jw-03-2002/jw-0315-jms_p=html
· DuBois, Paul. 使用、编程、管理MySQL 4数据库权威指南,第二版 。(www.bookpool.com/.x/d4jha9om4m/sm/0735712123)
· Oracle的可延迟约束支持:(http://download-west.oracle.com/docs/cd/B10501_01/se=ver.920/a96524/c22integ.htm#4666).
要求免费Oracle Technical Network (OTN)会员资格
· 于此处检验J2EE模式: (http://java.sun.com/blueprints/patterns/index.html).
示例程序中使用的Session Facade Pattern 请参考: http://java.sun.com/blueprints/corej2eepatterns/Patt=rns/SessionFacade.html 和 http://java.sun.com/blueprints/patterns/SessionFacad=.html.
· 示例程序使用中的Value Object Pattern请参考: http://java.sun.com/blueprints/corej2eepatterns/Patt=rns/TransferObject.html 和 http://java.sun.com/blueprints/patterns/TransferObje=t.html.
· JUnit,包括下载软件: www.junit.org/index.html
本文源代码下载网址:http://photos.sys-con.com/story/res/44845/source.html |