EJB中事务处理的两种方式

来源:互联网 发布:免费的收音机不用网络 编辑:程序博客网 时间:2024/06/05 10:04

EJB中事务处理的两种方式
EJB中处理事务有两种方式,一种是由容器管理事务,一种是由Bean管理事务,在任何Bean中都可以使用容器管理事务,会话Bean和消息驱动Bean可以使用Bean管理事务,实体Bean不能使使用Bean管理事务。
(
)、容器管理事务
    
容器管理事务简化了开发,因为企业Bean不用编码来显式制定事务界限。代码不包括开始结束事务的语句。典型的,容器会在一个企业Bean的方法被调用前立即开始一个事务,在这个方法退出以前提交这个事务。每个方法都关联一个事务。在一个方法中不允许嵌套或多个的事务存在。容器管理事务不需要所有的方法都关联事务。当部署一个Bean时,通过设定部署描述符中的事务属性来决定方法是否关联事务和如何关联事务
1
    事务的属性
一个事务的属性控制了事务的使用范围。method-A开始一个事务然后调用Bean-2中的method-B.它运行在method-A开始的事务中还是重新执行一个新的事务?结果要看method-B中的事务属性

一个事务属性可能有下面的属性之一:
☆ Required
☆ RequiresNew
☆ Mandatory
☆ NotSupported
☆ Supports
☆ Never


Required
如果客户端正在一个运行的事务中调用一个企业Bean的方法,这个方法就在这个客户端的事务中执行。如果客户端不关联一个事务,这个容器在运行该方法前开始一个新的事务。
Required
属性在许多事务环境中可以很好的工作,因此你可以把它作为一个默认值,至少可以在早期开发中使用。因为事务的属性是在部署描述符中声明的,在以后的任何时候修改它们都很容易。
RequiresNew
如果客户端在一个运行的事务中调用企业Bean的方法,容器的步骤是:
1
.挂起客户端的事务
2
.开始一个新的事务
3
.代理方法的调用
4
.方法完成后重新开始客户端的事务
如果客户端不关联一个事务,容器运行这个方法以前同样开始一个新的事务。如果你想保证该方法在任何时候都在一个新事物中运行,使用RequiresNew属性。
Mandatory
如果客户端在一个运行的事务中调用企业Bean的方法,这个方法就在客户端的事务中执行。如果客户端不关联事务,容器就抛出TransactionRequiredException 异常。
如果企业Bean的方法必须使用客户端的事务,那么就使用Mandatory属性。
NotSupported
如果客户端在一个运行的事务中调用企业Bean的方法,这个容器在调用该方法以前挂起客户端事务。方法执行完后,容器重新开始客户端的事务。
如果客户端不关联事务,容器在方法运行以前不会开始一个新的事务。为不需要事务的方法使用NotSupported属性。因为事务包括整个过程,这个属性可以提高性能。
Supports
如果客户端在一个运行的事务中调用企业Bean的方法,这个方法在客户端的事务中执行,如果这个客户端不关联一个事务,容器运行该方法前也不会开始一个新的事务。因为该属性使方法的事务行为不确定,你应该谨慎使用Supports属性。
Never
如果客户端在一个运行的事务中调用企业Bean的方法,容器将抛出RemoteException异常。如果这个客户端不关联一个事务,容器运行该方法以前不会开始一个新的事务。

 


(


(
) Bean管理事务
 
容器管理事务不支持嵌套事务,Bean管理事务支持嵌套事务,所以需要嵌套事务时可以采用Bean管理事务,使用Bean管理事务需要我们显式的设置事务的属性,需要我们自己编码管理事务,我门可以采用下面两种方式在Bean中管理事务
1
JDBC事务
JDBC
事务通过DBMS事务管理器来控制。你可能会为了使用会话Bean中的原有代码而采用JDBC事务将这些代码封装到一个事务中。使用JDBC事务,要调用 java.sql.Connection接口的commitrollback方法。事务启动是隐式的。一个事务的从最近的提交、回滚或连接操作后的第一个SQL的语句开始。(这个规则通常是正确的,但可能DBMS厂商的不同而不同),例如
public void ship (String productId, String orderId, int quantity) {
  try {
      //
需要通知DBMS不要自动提交每个SQL语句
      con.setAutoCommit(false);
      updateOrderItem(productId, orderId);
      updateInventory(productId, quantity);
      con.commit();

   } catch (Exception ex) {
       try {
          con.rollback();
          throw new EJBException("Transaction failed: " +
             ex.getMessage());
       } catch (SQLException sqx) {
           throw new EJBException("Rollback failed: " +
              sqx.getMessage());
       }
   }
}
2
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接口的begincommitrollback方法来确定事务界限(该接口只能在SessionBean中使用,实体Bean不允许使用用户自定义的)。下面选自TellerBean类的代码示范了UserTransaction的用法。begincommit方法确定了数据库操作的事务界限,如果操作失败则调用rollback回滚事务并抛出EJBException异常。

public void withdrawCash(double amount) {
  UserTransaction ut = context.getUserTransaction();
  try {
      ut.begin();
      updateChecking(amount);
      machineBalance -= amount;
      insertMachine(machineBalance);
      ut.commit();
   } catch (Exception ex) {
       try {
          ut.rollback();
       } catch (SystemException syex) {
           throw new EJBException
              ("Rollback failed: " + syex.getMessage());
       }
       throw new EJBException
          ("Transaction failed: " + ex.getMessage());
    }
}

) 、容器管理事务的回滚
在以下情况下,事务将回滚。
第一,    如果产生一个系统异常,容器将自动回滚该事务。
系统异常是指应用程序的支撑服务出现异常。这样的异常例子有:不能得到数据库连接,数据库满造成SQL语句插入失败,一个lookup方法找不到需要的对象等等。如果企业Bean遇到一个系统级的问题,它将抛出javax.ejb.EJBException,容器会把该异常包装到一个 RemoteException异常中返回给客户端。因为EJBExceptionRutimeException的子类,所以你不需要将它列在 throws子句中。当一个系统异常发生时,EJB容器可能会销毁企业Bean实例,因此系统异常不能被客户端处理,它需要系统管理员的干涉
第二,    由于EJBException作为系统异常,他继承自RutimeException,所以经过验证表明当抛出一个继承自 RutimeException的自定义异常时EJB容器也会自动回滚该事务,抛出普通的继承自Exception的应用程序异常容器不回自动回滚该事务
第三,    通过调用EJBContext接口SetRollbackOnly方法,Bean方法通知容器回滚该事务。如果Bean抛出一个普通的非继承自RutimeException应用异常,事务将不会自动回滚,但可以调用SetRollbackOnly回滚。例如
public class serviceRegBean implements SessionBean {
    SessionContext sessionContext;
    public void ejbCreate() throws CreateException {
    }
    public void ejbRemove() {
    }
    public void ejbActivate() {
    }
    public void ejbPassivate() {
    }
    public void setSessionContext(SessionContext sessionContext) {
        this.sessionContext = sessionContext;
    }
    public void updateData() throws   ThirdgsException {
        try {
           //
更新操作一
           //
更新操作二
        }
        catch (Exception ex) {
            //
发生异常回滚事务
            sessionContext.setRollbackOnly();
            ex.printStackTrace();
            throw new ThirdgsException();
        }
    }
}
 
其中的ThirdgsException为继承自Exception的异常 你可以为整个企业Bean或者单个方法指定事务属性。如果你为整个企业Bean和它某个方法各指定一个事务属性,为该方法指定的事务属性优先。当为单个方法指定事务属性时,不同类型企业Bean的要求也不同。会话Bean需要为商业方法定义事务属性,但create方法不需要定义事务属性。实体Bean需要为商业方法、create方法、remove方法和查找(finder)方法定义事务属性。Message-driven Bean需要为 onMessage方法指定属性事务,而且只能是RequiredNotSupported其中之一。

 

 

原创粉丝点击