技术开发 频道

漫谈WebSphere应用服务器之事务

2.J2EE事务

    网络就是计算机这个口号虽然没有造就一个互联网软件帝国,却让Java成为了企业级应用的首选。随着EJB编程模型在J2EE中的引入,JTA和JTS也随之发布。

    如下图所示,J2EE世界中的事务模型完全是延续DTP的。它也定义了应用、资源管理器和事务管理器。

    JTA协议简单来说就是用Java来定义了X/Open的DTP模型中的两组接口(TX和XA)。具体而言,JTA把应用程序分为了两类,一类是真正的客户应用程序,另一类是应用服务器。针对这两类事务客户端它分别定义了javax.transaction.UserTransaction和javax.transaction.TransactionManager接口,这两组接口直接对应了TX接口。通过UserTransaction接口,客户应用程序就可以显示的控制事务的开始和结束。但在J2EE的世界中更推崇让容器来管理事务,这样应用无需硬编码,只要通过声明式的方式就可以让自己的EJB运行在特定的事务上下文中。在J2EE规范中定义了好多种类型的事务属性,根据这些属性容器在调用EJB之前和之后就会执行相应的事务控制操作。比如如果事务属性设置为RequireNew:

    //在开始调用Bean方法之前,容器代码先拿到一个事务管理器对象。如何拿到
    //这个对象在规范中没有说明,因此不同的容器提供商有不同的方法。
    TransactionManager txManager = TransactionManagerFactory.getTransactionManager();

    //由于是需要新的事务,因此需要把当前已有的事务挂起(如果有事务的话)。
    Transaction current = txManager.suspend();

    //接下来就可以发起一个新的事务了。
    txManager.begin();

    //然后容器把请求发给EJB实例,业务逻辑开始执行。在执行过程中任何
    //事务相关的操作都会被自动的加入到当前事务中。最后执行完成推出。

    //容器重新接管控制权,如果没有异常,则提交当前事务。
    txManager.commit();

    //最后恢复被挂起的事务。
    txManager.resume(current);

    而XA接口则是由javax.transaction.xa.XAResource来提供的。该接口定义了资源管理器和事务管理器之间的契约。在上一章节中我们已经 简要的介绍过XA接口的方法。这儿需要注意的是在J2EE的环境下,open和close并不会被调用到,因此资源的初始化和关闭时由资源管理器自己完成的。

    而JTS相对而言就比较低层得多,它规范了一个J2EE下的事务管理器在上层需要提供对JTA的支持,而下层则需要实现OTS的Java映射。

    说到这儿,J2EE事务基本上可以告一段落。但其实还有一个问题是在上述的代码中,业务逻辑进行事务性操作的时候,比如往数据库里面加入一条记录,或者往JMS Queue中写入一条消息。这些资源是如何自动的加入到当前的事务中呢?这部分内容是不可能在J2EE的规范中找到的。目前绝大部分容器的实现都是在XA数据源上做的文章。比如我们在WebSphere应用服务器上定义了一个jdbc/Order的数据源,然后在一个Session Bean中用下面的示例代码来添加一个订单:

    InitialContext ic = new InitialContext();
    DataSource ds = (DataSource) ic.lookup("jdbc/Order");
    Connection con = ds.getConnection();
    Statement st  = con.createStatement();
    String sql ="insert into order .....";
    st.execute(sql);
    //最后cleanup
    st.close();
    con.close();

    在上述例子中,如果这个Session Bean的事务标记为Required、RequiredNew、Support,则这儿的数据库操作会自动加入到当前的事务中。如何自动加入的秘密就在于这儿返回的数据源。一个简单的实现是当ds.getConnection方法被调用时,数据源的实现里面首先调用底层的资源管理器拿到一个Connection,然后调用Connection的getXAResource拿到XAResource,接着拿到当前的transactionManager应用,然后通过transactionManager.getTranaction().enlistResource把该资源加到当前的事务中。最后返回一个Connection的封装。通过这种方式资源就被自动的加入到当前事务中,然后在业务逻辑执行完成后,当容器重新拿到控制权后,容器就会根据配置来调用事务管理器来完成事务的提交或者回滚。

0
相关文章