http://zh.objectweb.org/JOnAS/gb/PG_Transaction.html
事务处理行为
面向的读者和内容提要
本文面向的读者主要是企业bean的提供者,例如负责在服务器端开发组件的程序员。本文解释了如何定义EJB应用程序的事务处理.
以下是本文的内容提要:
-
面向的读者和本文的内容提要
-
声明性的事务管理
-
BEAN管理的事务
-
分布事务管理
声明性的事务管理
在容器管理事务这种事务管理方式的情况下,企业BEAN的事务处理行为是在配置时被定义的,具体体现在标准部署描述符文件中的集成描述符元素( assembly-descriptor element)部分中. 在配置时我们可以为同一BEAN中所有的方法(methods)同时定义一个共通的事务处理行为,也可以为每个方法( methods )分别定义不同的事务处理行为 . 我们通过指定事务属性来配置事务的行为.事务的属性有如下几种:
-
NotSupported:如果该方法是在一个事务上下文中被调用,那么该方法执行过程中,该事务将被挂起.
-
Required:如果该方法是在一个事务上下文中被调用,该方法在该事务上下文中执行.否则(该方法不在一个事务上下文中被调用),在该方法执行前,容器将自动生成一个新的事务,随后该方法在新的事务上下文中执行,并且在该方法结束时,容器将自动提交这个被自动生成新的事务.
-
RequiresNew:该方法总是要求在一个新的事务上下文中执行.在该方法执行前,容器将自动生成一个新的事务,并且在该方法结束返回时,容器将自动提交这个被自动生成的新事务.如果该方法是在一个事务上下文中被调用,那么新的事务开始时,该事务将被挂起,并且新事务结束后,该事务将重启.
-
Mandatory:该方法总是要求在一个事务上下文中被调用.否则,容器将抛出 TransactionRequired 例外.
-
Supports:该方法如果在一个事务上下文中被调用,那么该方法将在该事务上下文中执行.如果该方法的调用者不处在事务上下文中,那么该方法也就不在任何事务上下文中执行.
-
Never:该方法要求该方法的调用者不能处在事务上下文中.否则,容器将抛出 RemoteException 例外.
表格说明如下:
事务属性 |
调用者事务 |
企业BEAN方法(METHOD)的事务 |
NotSupported |
-
T1 |
-
- |
Required |
-
T1 |
T2
T1 |
RequiresNew |
-
T1 |
T2
T2 |
Mandatory |
-
T1 |
错误
T1 |
Supports |
-
T1 |
-
T1 |
Nervere |
-
T1 |
-
错误 |
根据EJB规范书要求,事务属性在部署描述符的集成描述符(assembly - descriptor)中设定,例如:
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>AccountImpl</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Supports</trans-attribute>
</container-transaction>
<container-transaction>
<method>
<ejb-name>AccountImpl</ejb-name>
<method-name>getBalance</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
<container-transaction>
<method>
<ejb-name>AccountImpl</ejb-name>
<method-name>setBalance</method-name>
</method>
<trans-attribute>Mandatory</trans-attribute>
</container-transaction>
</assembly-descriptor>
在本例中,对于AccountImpl bean的所有没有用container-transaction元素作明确指定的方法, 使用缺省事务属性Supports(匹配符*指定缺省事务属性,适用于该BEAN所有方法( method )).并且明确指定getBalance 和 setBalance 方法的事务属性分别是 Required 和 Mandatory (通过给定特定的 方法method名).
BEAN管理的事务
对于自己管理自己事务的BEAN,必须在标准部署描述符中设定其对应的 transaction-type元素.例如下:
<transaction-type>Bean</transaction-type>
对于BEAN自己管理的事务,BEAN程序员应该使用javax.transaction.UserTransaction来界定事务边界.该接口(interface)javax.transaction.UserTransaction由EJB服务器在服务器内部一个对象上实现.可以通过调用EJBContext.getUserTransaction()来获得该接口(这儿的EJBContext根据bean的种类session BEAN或entity bean的不同而不同, 在session bean 中 EJBContext指 SessionContext,而在 entity bean EJBContext指 EntityContext ).下面的就是一个例子,在 session bean的"doTxJob" 方法中界定事务边界; UserTransaction 对象(接口)通过 sessionContext对象获取.其中sessionContext对象在BEAN初始化方法 setSessionContext(BEAN初始化时自动被EJBserver调用)中作为参数传递过来.(这意味着BEAN程序员应该在setSessionContext中将该 sessionContext对象保存在BEAN的变量中).(参考 example of the session bean).
public void doTxJob() throws RemoteException {
UserTransaction ut = sessionContext.getUserTransaction();
ut.begin();
... // transactional operations
ut.commit();
}
另一个获得接口 UserTransaction 的方法是用 JNDI ,即在初始化上下文中通过使用 java:comp/UserTransaction名字来获取.
分布事务管理
正如前面部分所讲,一个应用程序的事务行为可以通过声明的方式来定义,也可以由BEAN或BEAN的调用者分别,或BEAN和BEAN的调用者协助,用编程的方式在代码中指定(界定事务边界).不管在哪中情况下,事务的分布特性这方面,无论对BEAN提供者(bean provider) 还是对应用集成商(application assembler.)来说都是完全透明的.这意味着一个事务可能有多个在不同的EJB服务器上的BEAN参与,而平台应该自己从全局角度管理分布事务.平台在多个不同的服务器间使用两相提交协议(two phase commit )来管理分布事务,从而BEAN程序员不用考虑事务的分布特性这方面.
在 been已经开发完成,并且应用集成结束后,部署人员 (deployer)或管理员( administrator )也可以将不同的BEAN配置分布在同一或多个不同的机器上的同一或多个不同的EJB服务器里.
这种配置过程可以在不涉及到代码的变动或部署描述符的修改的情况下完成.The distributed configuration is specified at launch time: in the environment properties of an EJB server, you may specify分布事务的配置是在EJB服务器启动时进行进行:所以分布事务的配置在EJB服务器的环境配置文件中设定.设定如下:
这须通过设定环境配置文件 jonas.properties 里的jonas.service.ejb.descriptors 和 jonas.service.jtm.remote项来完成.前一个列出该EJB服务器中管理的所有企业BEAN(通过指定部署描述符文件名或ejb-jar文件名),后一个设定Java Transaction Monitor(JTM)启动模式:
-
if set to false, the JTM is local, i.e. it will run into the same JVM as the EJB Server. 如果设为false,那么JTM使用本地方式,即该EJB服务器的JVM中同时启动一个JTM
例如:
jonas.service.ejb.descriptors Bean1.xml, Bean2.xml
jonas.service.jtm.remote false
JTM可运行在单独的JVM中,而不必一定运行于某个EJB服务器内.在这种情况下,可以如下命令文单独启动JTM:
TMServer
通过这种灵活的配置方式,就可根据资源(CPU或数据源)的具体情况而采用不同的配置,从而得到最佳的系统性能.
如下例图是针对三个企业BEAN而采用四种不同配置,
-
第1种情况: 三个企业BEAN B1, B2 and B3 分布在同一个EJB服务器内,EJB服务器内同时启动了一个Java Transaction Monitor.
-
第2种情况: 三个企业BEAN分别分布在不同的EJB服务器内,其中有只有一个EJB服务器内启动了一个Java Transaction Monitor,用于管理全局分布事务.
-
第3种情况:三个企业BEAN分别分布在不同的EJB服务器内,JTM运行在每个单独的JVM中.
-
第4种情况:三个企业BEAN分别分布在不同的EJB服务器内. 每个EJB服务器内启动了一个Java Transaction Monitor. 其中一个作为主监视器( master monitor),另外两个为附属监视器( slaves. )
这些不同的配置情况可通过配置EJB 服务器对应的环境属性配置文件,再启动 EJB 服务器来实现,有些情况下也要启动JTM(第3种情况).基本原则是应该根据资源的位置和负载均衡来作出合适的选择.以下几点说明,以供参考:
-
如果企业BEAN要求运行于同一台机器,并且要求相同的EJB服务器配置,第1种情况应该是最佳选择.
-
如果企业BEAN要求运行于不同机器,那么第4种情况应该是最佳选择.因为在这种情况下,本地方式的事务管理更加合适.
-
如果企业BEAN要求运行于同一台机器,而要求不同的EJB服务器配置,第2种情况应该是好的选择.