UML软件工程组织

EJB组件事务详解(1)
作者:苏洋 本文选自:赛迪网 2003年01月09日

 

会话、实体以及消息驱动类型EJB组件的运行,在不同程度上均依赖于数据库中存储的数据资源或者向数据库中存储数据信息。对于J2EE应用系统中与EJB组件相关的企业信息系统,必须保持其存数据的准确性、可靠性、一致性和时效性。例如,在金融领域的J2EE应用系统中,如果系统正在根据客户要求在两个账户之间进行转账。如果应用系统增加贷款账户的余额后,EJB服务器突然崩溃,应用系统没有减少借款账户的余额。这种情况下,对于一次转账操作来说没有正常结束,与EJB组件相对应的数据记录存在致命(fatal)错误,会给银行造成损失。为此,EJB规范定义了相应的组件事务(Transaction)管理方式,用于维护组件对应数据资源的一致性和稳定性。

在EJB2.0规范中定义了两种类型的组件事务:容器管理(Container-managed)事务和组件管理(Bean-managed)事务。组件程序设计人员以及组装人员可以针对组件类型以及事务管理策略选择组件事务管理的实现方式。


事务的容器管理方式


如果将组件的事务管理特性设置为容器管理方式,则需要组件部署的EJB容器负责设置组件中方法的事务范围并对事务的过程进行控制,组件程序设计人员不需要在组件的实现代码中编写事务管理代码,极大程度地简化了组件程序的开发过程。

事务属性

对于会话、实体以及消息驱动组件,均可以设置组件的事务特征为容器管理类型。当处于事务范围内的组件方法被调用后,EJB容器立即开始一个事务过程,直至该方法运行结束。

读者可能会认为设置组件的事务类型为容器管理类型时,客户端调用EJB组件中的每个方法均通知EJB容器启动一个事务过程,而实际情况不是这样。在容器管理事务类型的EJB组件组装过程中,可以通过设置组件的事务属性来指定EJB容器对组件的事务管理方式。EJB容器支持如下类型的事务属性:

◇Required:当处于事务范围内的客户端应用调用组件商务方法时,组件商务方法执行在原有的客户端事务范围内;

◇RequiredNew:当处于事务范围内的客户端应用调用组件商务方法时,EJB容器启动一个新的事务过程,组件商务方法执行在新事务过程范围内;

◇Mandatory:如果调用EJB组件商务方法的客户端应用不处于事务范围内,则EJB容器抛出TransactionRequiredException异常,强制客户端启动事务过程;

◇NotSupported:EJB组件的商务方法不需要运行在事务过程中。如果调用EJB组件方法的客户端应用处于事务过程中,则调用组件商务方法时原有事务过程挂起,直至组件方法运行结束;

◇Supports:组件方法必须处于事务范围内。如果调用组件商务方法的客户端不处于事务过程中,则EJB容器启动新的事务过程;

◇Never:组件方法不需要运行在事务过程中。如果调用组件商务方法的客户端应用处于事务范围内,则EJB容器抛出RemoteException异常。

在组件开发过程中可以为EJB组件设置上述组件事务属性或者只将上述属性应用于组件中的某个方法。需要注意的是:如果针对组件方法设置事务属性,不同类型EJB组件中的方法对于事务属性类型的要求不同。会话类型EJB组件容许针对组件的商务方法设置事务属性,不容许将创建组件的create方法包括在事务范围之内;实体类型EJB组件可以为组件商务方法、create、remove和find方法设置事务属性;消息驱动组件只容许将组件的onMessage方法设置为Required和NotSupported属性。

容器管理事务的回滚

采用容器管理事务类型的方法可以采用两种策略通知EJB容器将组件方法的运行结果回滚(Rollback)。一种策略是事务范围内的方法抛出系统异常,另外一种是在组件方法中调用EJBContext接口中的setRollbackOnly方法通知EJB容器。

当EJB容器将事务回滚时,通常撤销事务范围内的SQL语句对组件对应数据资源所做的所有改变。对于实体类型EJB组件,EJB容器撤销的是对组件中实例变量的改变;对于会话类型EJB组件,EJB容器通常调用SessionSynchronization接口中的方法将组件中所有的实例变量复位。

SessionSynchronization接口中包括三个方法:afterBegin、beforeCompletion和afterCompletion,分别用于在事务过程中的不同阶段将组件类中的实例变量与对应的数据库记录进行同步。

客户端调用EJB组件的商务方法之前,EJB容器调用afterBegin方法通知组件中的实例变量EJB容器已经启动一个新的事务过程,可以在该方法中将数据库中相应字段的值赋值给组件中的实例变量。

组件商务方法运行结束、事务提交之前EJB容器调用beforeCompletion方法。在该方法中可以将组件中的实例变量与其对应的数据库记录字段进行同步。

如果EJB容器调用afterCompletion方法,说明此时整个事务过程已经结束。该方法中逻辑类型的参数值如果为true,则表明事务范围内的方法运行成功,事务过程确认提交,反之EJB容器将整个事务过程中方法的运行结果回滚,EJB容器利用数据库记录中相应字段的内容更新组件的实例变量。


事务的组件管理方式


读者也许会认为利用容器事务管理方式完全能够满足EJB组件的事务要求。实际上,当处于事务范围内的组件方法运行时,组件部署的EJB容器必须完整控制组件的事务过程,这使得EJB组件对于自身方法的事务控制无能为力。另外,如果组件对应数据库服务器的变化将导致组件事务属性的重新设置。为了增强组件的事务控制能力以及不同数据库服务器之间的可移植性,EJB规范定义了另外一种类型的组件事务管理方式-事务的组件管理方式,使得组件程序设计人员能够在组件的实现代码中编写事务控制代码、设置事务控制范围,增强了组件事务控制的灵活性。需要注意的是:事务的组件管理方式仅适用于会话类型和消息驱动类型EJB组件,实体类型EJB组件只能采用事务的容器管理类型。

组件程序设计人员可以采用两种类型事务的组件管理方式:JDBC事务管理方式和JTA事务管理方式。

JDBC事务管理方式

为了理解JDBC事务管理方式,首先请读者看下面的代码:

public void doSomeThing() {
try{
con.setAutoCommit(false);
demoBusinessMethod();
con.commit();
}catch(Exception exp){
try{
con.rollback();
throw new EJBException("Transaction failed: " + exp.getMessage());
}catch(SQLException exp1){
throw new EJBException("Rollback failed: " + exp1.getMessage());
}
}
}


上述代码中的组件商务方法执行前,首先调用Connection对象实例con的setAutoCommit方法并在方法中指定参数false,通知数据库服务器不自动提交SQL语句的执行结果。当组件中的方法执行成功后,调用con对象实例中的commit方法提交所有的数据库操作结果。在方法执行过程中如果发生任何类型的异常均导致事务范围内所有方法的运行结果回滚。

JDBC事务管理方式是通过数据库管理系统的事务管理器(Transaction Manager)实现的。在该方式中,通过java.sql.Connection对象中的connect方法界定出事务的起始位置后,与相关对应的数据库管理器将启动一个事务过程。当组件方法运行结束后可以根据组件商务方法的运行情况调用commit方法向数据库提交运行结果或者调用rollback方法将事务范围内方法的运行结果回滚。



版权所有:UML软件工程组织