EJB2.0的事务处理(待续)
1.EJB事务分类
- 容器管理事务的回滚
你能够在任何企业Bean中使用容器管理事务:会话Bean、实体Bean或者 Message-driven Bean。容器管理事务可以分两种:
第一,如果产生一个系统异常,容器将自动回滚该事务。
第二,通过调用EJBContext接口SetRollbackOnly方法,Bean方法通知容器回滚该事务。如果Bean抛出一个应用异常,事务将不会自动回滚,但可以调用SetRollbackOnly回滚。
- bean管理事务
在一个Bean管理事务中,会话Bean或者Message-driven Bean是用代码显式设置事务界线的。实体Bean不能使用Bean管理事务,只能使用容器管理的事务。虽然容器管理事务Bean需要较少的代码,但它也有一个局限:方法执行时,它只能关联一个事务或不关联任何事务。如果这个局限使你Bean编码困难,你应该考虑使用Bean管理事务
其中bean管理事务可以分为JDBC事务
JDBC 事务
JDBC事务通过DBMS事务管理器来控制。你可能会为了使用会话Bean中的原有代码而采用JDBC事务将这些代码封装到一个事务中。使用JDBC事务,要调用java.sql.Connection接口的commit和rollback方法。事务启动是隐式的。一个事务的从最近的提交、回滚或连接操作后的第一个SQL的语句开始。(这个规则通常是正确的,但可能DBMS厂商的不同而不同)
JTA 事务
JTA是Java Transaction API 的缩写。这些API 允许你用独立于具体的事务管理器实现的方法确定事务界限。J2EE SDK 事务管理器通过Java事务服务(Java Transaction Service, JTS)实现。但是你的代码并不直接调用JTS中的方法,而是调用JTA方法来替代,JTA方法会调用底层的JTS实现。
JTA事务被J2EE 事务管理器管理。你可能需要使用一个JTA事务,因为它能够统一操作不同厂商的数据库。一个特定DBMS的事务管理器不能工作在不同种类的数据库上。然而J2EE事务管理器仍然有一个限制——它不支持嵌套事务。就是说,它不能在前一个事务结束前启动另一个事务。
要自己确定事务界限,可以调用javax.transaction.UserTransaction接口的begin、commit和rollback方法来确定事务界限(该接口只能在SessionBean中使用,实体Bean不允许使用用户自定义的)。
2.事务属性
Required
如果客户端正在一个运行的事务中调用一个企业Bean的方法,这个方法就在这个客户端的事务中执行。如果客户端不关联一个事务,这个容器在运行该方法前开始一个新的事务。
Required属性在许多事务环境中可以很好的工作,因此你可以把它作为一个默认值,至少可以在早期开发中使用。因为事务的属性是在部署描述符中声明的,在以后的任何时候修改它们都很容易。
RequiresNew
如果客户端在一个运行的事务中调用企业Bean的方法,容器的步骤是:
1.挂起客户端的事务
2.开始一个新的事务
3.代理方法的调用
4.方法完成后重新开始客户端的事务
如果客户端不关联一个事务,容器运行这个方法以前同样开始一个新的事务。如果你想保证该方法在任何时候都在一个新事物中运行,使用RequiresNew属性。
Mandatory
如果客户端在一个运行的事务中调用企业Bean的方法,这个方法就在客户端的事务中执行。如果客户端不关联事务,容器就抛出TransactionRequiredException 异常。
如果企业Bean的方法必须使用客户端的事务,那么就使用Mandatory属性。
NotSupported
如果客户端在一个运行的事务中调用企业Bean的方法,这个容器在调用该方法以前挂起客户端事务。方法执行完后,容器重新开始客户端的事务。
如果客户端不关联事务,容器在方法运行以前不会开始一个新的事务。为不需要事务的方法使用NotSupported属性。因为事务包括整个过程,这个属性可以提高性能。
Supports
如果客户端在一个运行的事务中调用企业Bean的方法,这个方法在客户端的事务中执行,如果这个客户端不关联一个事务,容器运行该方法前也不会开始一个新的事务。因为该属性使方法的事务行为不确定,你应该谨慎使用Supports属性。
Never
如果客户端在一个运行的事务中调用企业Bean的方法,容器将抛出RemoteException异常。如果这个客户端不关联一个事务,容器运行该方法以前不会开始一个新的事务。
例子:
假设有两个EJB,EJB1和EJB2。EJB1的method1中n次调用EJB2的method2.典型代码如下:
method1{
for(int i=0;i<n;i++){
EJB2的method2..
}
}
如果在for循环到第j次异常.那么如果method1为Required,method2为Required,则会回滚所有的操作.结果就是
method2 对于i从0--j的所有数据库操作都回滚.method1也回滚.因为都是同一个事务
如果在for循环到第j次一场,那么如果method1为Required,method2为RequirsNew,则不会回滚所有的操作.结果就是method2对于i从0--j的所有数据库操作都不回滚.但method1回滚.因为对于不同的i值.都为新的事务。
如果想让程序执行i从0--n次.那么需要记录执行正常和不正常的情况.此时只要try,catch 其中EJB的method2就可.在catch代码中记录异常情况.这样因为没有再throw异常给method1。代码可以一直执行n次。达到记录正常和异常的记录。当然对method1不使用事务,method2使用required也可以达到目的.对method1不使用事务的简单方法就是 设置其为Bean管理EJB,并在代码中不手动开启事务