2009年3月29日星期日

WLS_068:使用UserTransaction实现全局事务之二:在EJB上增加事务属性

开发运行环境:JDeveloper 11.1.2.4 + Oracle XE Database 11gR2
本文最后一次修改日期:2013-06-16

上一个例子中,方法doTran1和doTran2是在一个类中,实际情况中,这两个方法往往来自不同的类,比如可能来自两个不同的EJB。这时,如何保证全局的事务呢?

测试环境:1个WebLogic Server,两个Oracle XE数据库,其中WebLogic Server上建立了两个DataSource指向两个Oracle XE数据库;两个EJB,部署到同一个WebLogic Server上。

1. 创建EJB




右键选择增加的方法:doTran1,选择暴露到Remote和Local Interface中。
同时,注意到我们可以在doTran1方法上增加事务属性,这里我们选择TransactionAttributeType.REQUIRED。

EJB 完整代码如下(另一个EJB也是同样的逻辑):

package model;

import java.sql.Connection;

import java.sql.Statement;

import javax.annotation.Resource;

import javax.ejb.SessionContext;
import javax.ejb.Stateless;

import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;

import javax.sql.DataSource;

@Stateless(name = "DoTran1SessionEJB", mappedName = "XATest-Model-DoTran1SessionEJB")
public class DoTran1SessionEJBBean implements DoTran1SessionEJB, DoTran1SessionEJBLocal {
    @Resource
    SessionContext sessionContext;

    @Resource(name = "jdbc/hr1DS")
    DataSource hr1DS;

    public DoTran1SessionEJBBean() {
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void doTran1() throws Exception {
        System.out.println("Hello doTran1");
        Connection hr1 = hr1DS.getConnection();
        hr1.setAutoCommit(false);
        Statement stm1 = hr1.createStatement();
        stm1.execute("DELETE FROM jobs WHERE job_id='CEO1'");
        stm1.execute("INSERT INTO jobs VALUES('CEO1', 'CEO1', 1,2)");
        stm1.close();
        if (hr1 != null)
            hr1.close();
    }
}

注意这里使用了依赖注入的方式“注入了”DataSource。

2. 创建每个EJB测试的Client类,确保测试成功。

3. 根据每个EJB测试的Client类,创建一个测试两个EJB的Client类。

package model;

import java.util.Hashtable;

import javax.naming.CommunicationException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import javax.transaction.UserTransaction;

public class DoTranSessionEJBBeanClient {
    public DoTranSessionEJBBeanClient() {
        super();
    }

    public static void main(String[] args) {
        UserTransaction tran = null;
        try {
            final Context context = getInitialContext();
            tran = (UserTransaction)context.lookup("javax.transaction.UserTransaction");
            tran.begin();

            DoTran1SessionEJB doTran1SessionEJB =
                (DoTran1SessionEJB)context.lookup("XATest-Model-DoTran1SessionEJB#model.DoTran1SessionEJB");
            doTran1SessionEJB.doTran1();

            DoTran2SessionEJB doTran2SessionEJB =
                (DoTran2SessionEJB)context.lookup("XATest-Model-DoTran2SessionEJB#model.DoTran2SessionEJB");
            doTran2SessionEJB.doTran2();

            tran.commit();
        } catch (CommunicationException ex) {
            System.out.println(ex.getClass().getName());
            System.out.println(ex.getRootCause().getLocalizedMessage());
            System.out.println("\n*** A CommunicationException was raised.  This typically\n*** occurs when the target WebLogic server is not running.\n");
        } catch (Exception e) {
            e.printStackTrace();
            try {
                tran.rollback();
            } catch (Exception ex) {
                System.out.println("Rollback Exception: " + ex);
            }
        }
    }

    private static Context getInitialContext() throws NamingException {
        Hashtable env = new Hashtable();
        // WebLogic Server 10.x connection details
        env.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
        env.put(Context.PROVIDER_URL, "t3://127.0.0.1:7101");
        return new InitialContext(env);
    }
}

4. 测试
测试结果应该和上一个实验一样。

Project 下载:XATest.7z

没有评论: