2009年3月29日星期日

WLS_067:使用UserTransaction实现全局事务之一:基本用法

开发运行环境:WebLogic 12.1.1 开发版 + Oracle XE Database 11gR2

本文最后一次修改日期:2013-06-16

测试环境:1个WebLogic Server,两个Oracle XE数据库,其中WebLogic Server上建立了两个DataSource指向两个Oracle XE数据库。

测试代码如下:

import java.util.Hashtable;

import java.sql.Connection;
import java.sql.Statement;
import javax.sql.DataSource;

import javax.naming.Context;
import javax.naming.InitialContext;

import javax.transaction.UserTransaction;

import oracle.jdbc.xa.client.OracleXADataSource;

public class UserTransactionXATest {
    private static Context context = null;

    public static void main(String[] args) {
        UserTransactionXATest test = new UserTransactionXATest();
        UserTransaction tran = null;
        context = getInitialContext();

        try {
            tran = (UserTransaction)context.lookup("javax.transaction.UserTransaction");
            tran.begin();
            test.doTran1();
            //int divideBy0 = 5/0;
            test.doTran2();
            tran.commit();
        } catch (Exception e) {
            e.printStackTrace();
            try {
                tran.rollback();
            } catch (Exception ex) {
                System.out.println("Rollback Exception: " + ex);
            }
        }
    }

//        public static void main(String[] args) {
//            UserTransactionXATest test = new UserTransactionXATest();
//            context = getInitialContext();
//            try {
//                test.doTran1();
//                test.doTran2();
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
//        }

    public void doTran1() throws Exception {
        Connection hr1 = null;
        hr1 = getConnection("jdbc/hr1DS");
        //hr1 = getXAConnection("192.168.0.101");
        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();
    }

    public void doTran2() throws Exception {
        Connection hr2 = null;
        hr2 = getConnection("jdbc/hr2DS");
        //hr2 = getXAConnection("192.168.0.103");
        hr2.setAutoCommit(false);
        Statement stm2 = hr2.createStatement();
        stm2.execute("DELETE FROM jobs WHERE job_id='CEO2'");
        stm2.execute("INSERT INTO jobs VALUES('CEO2', 'CEO2', 1,2)");
        stm2.close();
        if (hr2 != null)
            hr2.close();
    }

    private static Context getInitialContext() {
        try {
            Hashtable env = new Hashtable();
            env.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
            env.put(Context.PROVIDER_URL, "t3://127.0.0.1:7001");
            //env.put(Context.SECURITY_PRINCIPAL, "weblogic");
            //env.put(Context.SECURITY_CREDENTIALS, "welcome1");
            return new InitialContext(env);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static Connection getConnection(String jndi) throws Exception {
        DataSource ds = (DataSource)context.lookup(jndi);
        Connection conn = ds.getConnection();
        return conn;
    }

    public static Connection getXAConnection(String ip) throws Exception {
        OracleXADataSource oxaDS = new OracleXADataSource();
        oxaDS.setDatabaseName("XE");
        oxaDS.setServerName(ip);
        oxaDS.setPortNumber(1521);
        oxaDS.setUser("hr");
        oxaDS.setPassword("hr");
        oxaDS.setURL("jdbc:oracle:thin:@" + ip + ":1521:XE");
        return oxaDS.getXAConnection().getConnection();
    }
}

(1)测试1:代码如上。
结果:不抛出异常:hr1和hr2的数据都成功正确插入各自的数据库库了。

(2)测试2: 暂停HR2 DataSource,这时会抛出异常:Caused by: java.sql.SQLException: Internal error: Cannot obtain XAConnection weblogic.common.resourcepool.ResourceDisabledException: Pool HR2 JDBC Data Source is Suspended, cannot allocate resources to applications.

结果:hr1和hr2的数据都没有插入各自的数据库库了,和我们预期的一样。 因为doTran2()方法抛出异常,导致doTran1()中的事务回滚了。

这时,笔者有一个疑问,如果不使用UserTransaction会怎样呢?
(3)测试3:在测试2的基础上,注释main函数(使用了UserTransaction),打开另一个main函数(没有使用UserTransaction)。
结果:hr1和hr2的数据依然没有插入各自的数据库库了, doTran2()方法抛出异常,依然导致doTran1()中的事务回滚了。
似乎使用UserTransaction和不使用UserTransaction没有什么区别。

(4)测试4:在测试3的基础上,设置doTran1和doTran2中的setAutoCommit(true);,取代原来的设置false。
结果:hr1的数据插入数据库库了,而hr2的数据没有插入数据库。虽然doTran2()方法抛出异常,但并没有影响doTran1()中的事务。

(5)测试5:在测试4的基础上,注释main函数(没有使用UserTransaction),打开另一个main函数(使用了UserTransaction)。
结果:hr1和hr2的数据都没有插入各自的数据库库了,和我们预期的一样。
doTran2()方法抛出异常,导致doTran1()中的事务回滚了。也就是说,UserTransaction的全局事务还是起作用了。

参考文献:
1. http://www.oschina.net/question/234345_51230

没有评论: