JTA 在Weblogic中的使用实例

晨曦之光 发布于 2012/04/25 16:18
阅读 2K+
收藏 2
在复杂的J2EE应用中,如果涉及到要在一个事务中将数据保存到多个数据库,或者在一个事务中同时要操作数据库资源和JMS资源,
为了保证数据在多个参入的数据源中的一致性,就需要用到JTA来控制事务,参入的数据源也需要支持X/Open协议(两阶段提交).
本文简单介绍如何在weblogic中使用JTA和解释JTA的TransactionManager是怎么定义事务边界和提交回滚事务的.
JTA的使用:
1,通过JNDI得到TransactionManager,然后可以用TransactionManager的begin,commit等方法来控制事务.
traMgr = (TransactionManager) context.lookup("javax.transaction.UserTransaction");
2,获取在weblogic上定义的datasource,datasource必须支持XA.
DataSource ds1 = (DataSource)context.lookup("DSORCL");
3,用TransactionManager声明事务开始,通过DataSource操作数据库,然后commit或者rollback事务.
traMgr.begin();
...//通过DataSource得到connection,然后操作数据库.
traMgr.commit();或者traMgr.rollback();
有时候,数据源可能不是在weblogic上配置的,或者是从不同的APP server上获取的(不过这种情况一般比较少).需要利用
TransactionManager.enlistResource(XAResource)主动的把这种资源加入到当前的事务管理中来.而对于从weblogic上
配置的DataSource,TransactionManager声明事务后,DataSource可以自动的发现并加入当前的事务.TransactionManager在
begin()的时候会将当前的事务信息绑定到当前的线程上.

Java代码示例:

public class TraMgrExample { 
    public void executeTra1(Connection conn) throws SQLException{
        PreparedStatement pstmt = conn.prepareStatement("Insert into A values(3,'VAL1')");           
        pstmt.executeUpdate();
        pstmt.close();
    }
    public void executeTraOutWlS(Connection conn ) throws SQLException{
        PreparedStatement pstmt = conn.prepareStatement("Insert into B values(1,'TRANSACTION MANAGER TEST')");           
        pstmt.executeUpdate();
        pstmt.close();
    }

    public void testGlobalTransaction() {
        System.out.println("testGlobalTransaction.");
        TransactionManager traMgr = null;
        Connection conn1 = null;
        Connection conn2 = null;
        try {               
            Context context = new InitialContext();
            DataSource ds1 = (DataSource)context.lookup("DSORCL");
            System.out.println("ds1." + ds1);
            conn1 = ds1.getConnection();
            conn1.setAutoCommit(false);                               
            traMgr = (TransactionManager) context.lookup("javax.transaction.UserTransaction");
            System.out.println("traMgr." + traMgr);   
            traMgr.begin();       
            XADataSource xads1 = getXADS1();//这个数据源是通过JDBC配置的
            XAConnection xaConn1 = xads1.getXAConnection();
            XAResource xaRes1 = xaConn1.getXAResource();   
            traMgr.getTransaction().enlistResource(xaRes1);//需要主动的加入到当前的事务中       
            conn2 = xaConn1.getConnection();
            conn2.setAutoCommit(false);
            executeTraOutWlS(conn2); 
            executeTra1(conn1);//通过在weblogic上配置的DataSource,会自动加入到当前的事务中. 
            traMgr.commit();
            System.out.println("finished.");  
        } catch (Exception e) {    
            try {
                traMgr.rollback();
                System.out.println("Exception happened, roll back all the transactions managed by traMgr.");
            } catch (IllegalStateException e1) {
                e1.printStackTrace();
            } catch (SecurityException e1) {
                e1.printStackTrace();
            } catch (SystemException e1) {
                e1.printStackTrace();
            }     
            e.printStackTrace();
        }finally{
            try {
                conn1.close();
                conn2.close();  
            } catch (SQLException e) {
                e.printStackTrace();
            }     
        }
    }

    public XADataSource getXADS1() throws SQLException {
        OracleXADataSource oxaDS = new OracleXADataSource();
        oxaDS.setDatabaseName("ORCL");
        oxaDS.setServerName("localhost");
        oxaDS.setPortNumber(1521);
        oxaDS.setUser(DemoConstant.UID);
        oxaDS.setPassword(DemoConstant.PWD);
        oxaDS.setURL("jdbc:oracle:thin:@localhost:1521:ORCL");
        return oxaDS;
    }

}
*在测试的时候,将两个OracleXADataSource(两个不同的数据库)以enlistResource的方式让Weblogic的JTA来管理的时候,碰到XAER_NOTA : The XID is not valid错误,不知道是weblogic的bug还是限制,这种情况应该将数据源配置到Weblogic server上,通过JNDI方式来访问.另外,从standalone的JAVA代码中虽然能够得到weblogic的JTA TransactionManager,但是不能用它进行事务管理,错误:You may enlist a resource only on a server.就是说weblogic的JTA TransactionManager只能在代码(war或者ear)发布到weblogic的server上才能使用.

weblogic的JTA主要是通过将当前事务绑定到线程来达到TransactionManager和DataSource之间的协调的.下面通过一些JAVA代码来模拟这中协调.主要是演示线程绑定,对于两阶段提交,恢复和一些细节没有做考虑.

1,下面这两个类负责保存和线程相关的Connection:(weblogic是通过InheritableThreadLocal来保存线程相关的事务信息)

public class JTAInfo {
    private static Map<Thread,JTAConnections> jtaInfo = new HashMap<Thread,JTAConnections>();
    public static Map<Thread, JTAConnections> getJtaInfo() {
        return jtaInfo;
    }
    public static void setJtaInfo(Map<Thread, JTAConnections> jtaInfo) {
        jtaInfo = jtaInfo;
    }
}

public class JTAConnections {
    private List<Connection> connections = new ArrayList<Connection>();
    public List<Connection> getConnections() {
        return connections;
    }
    public void setConnections(List<Connection> connections) {
        this.connections = connections;
    }       
}

2,下面这个类模拟weblogic提供的DataSource:

public class XADataSource {
    static {
        try {
            Class.forName("oracle.jdbc.driver.OracleDriver");
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    public static Connection getConnection(String sid, String uid, String pwd) throws SQLException {
        Connection conn = DriverManager.getConnection("jjdbc:oracle:thin:@localhost:1521:" + sid, uid, pwd);
        conn.setAutoCommit(false);
        //每次获取连接的时候,把这个connectin和当前的事务关联起来
        JTAInfo.getJtaInfo().get(Thread.currentThread()).getConnections().add(conn);     
        return conn;
    }
}
3,下面这个类模拟TransactionManager:

public class TransactionManager {
    public void begin() {
        if (JTAInfo.getJtaInfo().get(Thread.currentThread()) == null) {
            JTAInfo.getJtaInfo().put(Thread.currentThread(), new JTAConnections());
        }
    }
    public void enlistResource(Connection conn) {
        JTAConnections jtaConnes = JTAInfo.getJtaInfo().get(Thread.currentThread());
        jtaConnes.getConnections().add(conn);
    }
    public void commit() throws Exception {
        List<Connection> connections = JTAInfo.getJtaInfo().get(Thread.currentThread()).getConnections();               
        try {
            for (Connection conn : connections) {
                conn.commit();
            }
        } finally {
            try {
                for (Connection conn : connections) {
                    conn.rollback();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    public void rollback() throws Exception {
        List<Connection> connections = JTAInfo.getJtaInfo().get(Thread.currentThread()).getConnections();
        try {
            for (Connection conn : connections) {
                conn.rollback();
            }
        } finally {
            try {
                for (Connection conn : connections) {
                    conn.rollback();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
4,一个使用这个模拟的客户端代码:
public class Main {
    public static void tra1() throws Exception {
        Connection conn = XADataSource.getConnection("ORCL", "yorker", "yorker");
        Statement sta = conn.createStatement();
        sta.executeUpdate("INSERT INTO A VALUES(1,'val1')");
        sta.close();
    }
    public static void tra2() throws Exception {
        Connection conn = XADataSource.getConnection("ORCL", "yorker", "yorker");
        Statement sta = conn.createStatement();
        sta.executeUpdate("INSERT INTO B VALUES(2,'val2')");
        sta.close();
    }
    public static void main(String[] args) {
        TransactionManager trMgr = new TransactionManager();
        trMgr.begin();
        try {
            tra1();
            tra2();
            //trMgr.enlistResource(conn);//如果不是从模拟的datasource获取的连接,可以显示的加入到当前事务.
            trMgr.commit();
        } catch (Exception e) {   
            try {
                trMgr.rollback();
            } catch (Exception e2) {
                e2.printStackTrace();
            }           
            e.printStackTrace();
        }
    }
}


原文链接:http://blog.csdn.net/kkdelta/article/details/5579142
加载中
返回顶部
顶部