Thursday, July 02, 2009

자바로 구현하는 트렌젝션 프로그래밍(2)

자바로 구현하는 트렌젝션 프로그래밍(2)




자바스터디 네트워크 [www.javastudy.co.kr]

조대협 [bcho_N_O_SPAM@j2eestudy.co.kr]

 

1.   Java transaction

 

그럼 이제부터 자바에서 어떻게 트렌젝션을 처리하게 되어 있는지 구조를 살펴보고, 각각의 API들에 대해서 간단하게 살펴보도록 하자.

Java Transaction Model

 

Java Transaction 구성하는 API로는 크게 JTS(Java Transaction Service) JTA (Java Transaction Application) 구성이 된다.

 

JTS Transaction Manager 대한 Spec이고, JTA Application, Application Server, Resource Manager들간의 Interface 규약등을 정의하는 Spec이다.

 

일반적으로, Java 직접 Transaction Programming 할경우에는 JTA Interface 통해서  JTS 사용하게 된다. 쉽게 이야기 해서 JTS Transaction Manager, 그리고 JTA Transaction Manager 외부 인터페이스로 이해하면 된다.

 

이미 알고 있는 사람도 있겠지만, JTS 지원하는 Transaction Manager간에는 Global Transaction 가능하다. 예를 들면 WebLogic에서 EJB들을 호출하고, EJB들에서 IBM Websphere EJB 호출하면, 그것이 하나의 트렌젝션으로 묶어서 처리할 있다는 이야기다.

 

 이것이 가능한 이유는, JTS 구현된 Transaction Manager CORBA OTS(Object Transaction Service)라는 프로토콜로 Transaction Manager간에 통신을 하기 때문에,  하나의 Global Transaction으로 처리가 가능하게 되는 것이다.

 

<그림 2. JAVA Transaction API들간의 관계 >

 

그러면 각각의 Java Transaction API들을 살펴보도록 하자.

 

JTA

 

그러면 이런 일련의 트렌젝션 과정이 Java에서는 어떻게 구현되는지를 간단하게 살펴보고 넘어가도록 하자. Java에는 트렌젝션을 처리하기 위한 API Java Transaction API(이하 JTA) 제공한다. JTA에는 TM,AP,RM 상호작용을 정의하기 위해서, 아래와 같이 주요 다섯가지 인터페이스를 정의하고 있다.

 

- User Transaction Interface

- Transaction Manager Interface

- Transaction Interface

- XAResource Interface

- Xid Interface

 

1) User Transaction Interface

 

javax.transaction.UserTransaction 클래스로, AP TM간의 인터페이스를 나타낸다.

실제로 JTA 이용해서 프로그래밍을 할때는 User Transaction Interface 사용한다.( 우리가 직접 Transaction Programming 할때, 직접적으로 사용하게 되는 Interface.)

 

EJB Server내에서의 구현은

UserTransaction utx = ctx.getUserTransaction();

 

// start Transaction

utx.begin();

 

// do transaction

 :

 

utx.commit();

 

이런식으로 구현된다. ( 이렇게 EJB내에서 구현할때는 Transaction Model TX_BEAN_MANAGED 일때만 사용한다.-Bean Managed Transaction)

 

2) Transaction Manager Interface

 

javax.transaction.TransactionManager interface, TM  Application Server간의 인터페이스를 정의한다. 주로 트렌젝션간의 경계(boudary) 관리한다.

 하나의 트렌젝션에 대해서 Transaction Context 가지게 하고, 트렌젝션을 사용하는 Thread들간의 연관관계를 정의한다. 고로, 여러 Thread 하나의 Transaction으로 묶이는것과 같은 Global Transaction(분산 트렌젝션) 가능해지는 것이다.

 

 Transaction Manager Interface에서는 트렉젠셕과의 경계 관리 다음과 같은 원리로 수행하게 된다.

Transaction Context 관리하고, 각각의 Transaction Context Transaction object 의해 encapsulation 한다. 트렌젝션을 사용하는 모든 쓰레드들은 Transaction Context 대한 reference 가지게 되고, 만약 트렌젝션을 사용하지 않는 쓰레드는 값을 null 세팅한다.

 

이렇게 Transaction Manager Transaction 관리하기 위해서는 몇가지 주요 기능을 제공하는데, 기능들은 아래와 같다.

 

Starting a Transaction

전체 트렌젝션을 시작한다. 단계에서, Transaction object Transaction Context 해당 Thread Binding한다.

 

Completing a Transaction

TransactionManager.commit/rollback 이용해서, 현재 commit 호출한 Thread 트렌젝션을 완료(commit)한다. 트렌젝션의 완료가 끝나면, Thread Transaction Context null 세트한다.

 

Suspending and Resuming Transaction

현재 calling Thread 수행중인 Transaction suspend하거나, resume시킬 있다. Transaction 수행코드중간에, suspend 시키면, suspend중에 수행된 명령(SQL) Transaction 포함되지 않는다.

 

3) Transaction Interface

 

Transaction Interface 트렌젝션을 수행하기 위한, Transaction 자체의 정보를 기억한다. , 트렌젝션을 수행하기 위해서 필요한, Resource 목록을 기록하고, 트렌젝션의 commit rollback 관리한다.

 

 Transaction 생성되면, Transaction 관여 되는 Resource( RDBMS etc..) 들의 List Transaction object 바인딩 한다. (transaction.enlistResouce)

  Transaction object 관련된 Resource list 유지하고 있기 때문에. TM 현재 Transaction 관련된 RM 일괄적으로 Control ( commit시키거나, rollback 시키는것들) 가능하게 된다.

 

 그외에도, Transaction 대한 Equality Check Hash code 관리, synchronization 관리등을 수행한다. 자세한 내용은 JTA Spec 참고하기 바란다.

 

4) XAResource Interface

 

TM RM간의 인터페이스를 정의한다. X/OPEN XA Spec 따른 Resource Manager Implementation Java 표현해놓은 것이다. 

 각각의 Resource마다, XAResource Interface 제공되는데, 각각의 Resource local transaction begin,commit,prepare등을 수행한다. 각각의 Resource dependent되는 만큼, XA Interface Implementation Class들은 JDBC Driver 제공하는  vendor쪽에서 제공하게 된다.

 

XAResource Interface 대략적인 흐름을 보면 다음 코드와 같다.

 

 

XADataSource xaDS;

XAConnection xaCon;

XAResource xaRes;

Xid xid;

Connection conn;

Statement stmt;

int ret;

 

xaDS = getDataSource(); // vendor에서 제공되는 코드를 사용

xaCon = xaDS.getXAConnection("jdbc_user","jdbc_password");

xaRes = xaCon.getXAResource();

 

con = xaCon.getConnection();

stmt = conn.createStatement();

 

// create new global transaction id

xid = new MYXid(formatId,globalTransactionId,branchQualifier);

 

try{

  xaRes.start(xid,XAResource.TMNOFLAGS); // start transaction

  stmt.executeUpdate(sql);

  xaRes.end(xid,XAResource.TMSUCESS); // end transaction

 

  ret = xaRes.prepare(xid); // prepare

  if(ret == XAResource.XA_OK) xaRes.commit(xid,false); // commit

}catch(Exception e){

}finally{

stmt.close();

conn.close();

xaCon.close();

 

< 예제. 하나의 Resource 대해서 하나의 트렌젝션을 수행하는 예제 >

 

위의 코드 처럼, Resource마다, 트렌젝션을 구별하는 것은 각각의 트렌젝션의 ID, xid 이용해서, 어떤 트렌젝션인지를 구별한다. XA Interface 이용한 프로그래밍은 뒤에서 Oracle WebLogic XA Interface 이용한 예제에서 자세히 살펴보도록 하자.

 

5) Xid Interface

 

Xid 각각의 트렌젝션을 식별하기 위한 global transaction ID Java 구현해놓은 Interface이다. 여기에는 X/Open XID structure 따른 값이 들어가 있으며, transaction format ID,global transaction ID,branch qualifier 세가지 정보가 저장된다.

 

JTS

JTA Support in the Application Server

 

그러면 다음으로, JTA/JTS 인터페이스들이 어떻게 Java Application Server에서 서로 상호 작용을 하는지 알아보도록 하자.

 

( 내용은, Application Server 내부에서 어떻게 각각의 클래스와 인터페이스가 상호 작용을 하고, 작동원리가 어떻게 되는지를 살펴보기 위한것이다. 일반적인 트렌젝션 프로그래밍을 할때는   알아둘 필요는 없으니 참고만 하도록 하자. )

 

 

Application

Application

Server

TM

Resource

Adapter

 

 

 

 


TM : Transaction Manager

 

 

일반적으로 Application, Application Server 통해서, Transaction 수행하는 모델의 위의 그림과 같다. Application Application Server 접속해서 Connection 얻어서 Transaction 수행하게 되고,  Application Server내에서는 Transaction Manager 이용해서 Transaction 관리를 하게 되며, Transaction Manager Resource vendor (eg. SAP,Oracle,Message Queue etc..) Resource Adapter 이용해서, 각각의 Resource (eg. ERP,RDBMS etc.) 접근을하여, Transaction 제어를 하게 된다.

 

Resource Adapter vendor에서 제공되는데, JDBC Driver Package 같은것이 Resource Adapter 대표적인예가 된다. Resource Adapter내에는 여러클래스가 있는데, 크게 4가지 종류로 나누어 있다. ResourceFactory, Transactional Resource, Connection, XAResouce 이다.

 

ResourceFactory Transactional Resource 생성하는 역할을한다. RDMS에서 XADataSource 분류에 속한다.

여기서 생성된 Transactional Resource 직접 Resource로의 Connection(XAConnection) 연결하고, 해당 Resource Resource Manager 접근하기 위한 Interface 제공하며, Application에서 사용할 Connection (DB Connection)객체와 Transaction Manager에서 사용할 XAResource Interface 제공한다. 아래 그림을 보면서 다시 정리 해보도록 하자.

 

 

 

 

Application Server Transaction Manager, Java Application 상호 작용을 하게 되어 있다. Application Server Transaction Manager에게는 XAResource, 그리고, JavaApplication에게는 Connection 객체를 넘겨준다. Application Server 자체는, 각각의 Resource들과 열결될 있는 Transactional Resource (XAConnection) 가지고 있다.

 

이를 하나의 가상 시나리오로  정리를 해보자

 

 

1.       Java Client에서 TX_REQUIRED 트렌젝션 속성을 가지고 있는 EJB CALL 한다. Java Client에서는 Transaction 정의를 하지 않았다고 가정하면, Transaction EJB에서 부터 시작된다. Application Server Transaction Manager에게 Global Transaction 시작하도록 한다. TransactionManager.begin

2.       Transaction 시작되었으면, Java Application 데이타베이스를 접근하기 위해서 DB Connection 요청한다.

3.       Application Server JDBC 드라이버(resource adapter) 접근하여,  XADataSource (Resource Factory) 객체를 얻어온다.

4.       XADataSource 부터, XAConnection(Transactional Resource) 얻어온다. (getTransactionalResource)

5.       XAConnection , XAResource, Connection 얻어온다.

6.       Application server 이렇게 얻어온, XAResource Transaction 포함시키고 (enlistResource), XAResource Interface 이용하여, 각각의 Resource 하여금 Transaction 시작하도록 한다. (start)

7.       Application server XAConnection으로 부터 얻어온 DBConnection Java Application에게 넘겨준다. (getConnection/returnConnection)

8.       Java Application 받아온 Connection 이용하여 Transaction 수행하고, Connection close한다. (application performs operations, close)

9.       Connection close되면, Application Server 각각의 Resource Transaction으로부터 해제하고, (delistResource) 각각의 Resource에게 Transaction 끝났음을 알린다. (end)

10.   Application Sever에서 Transaction commit하면, Transaction Manager 각각의 XAResource Interface 통해서, 각각의 Resource prepare commit 메세지를 보내서 Transaction 완료한다. (prepare,commit)

 

 

 

 

 

2.   Java Transaction Programming

 

많은 경우에 Java에서 Transaction Programming 할경우에는 EJB 통해서 Application Server 자동적으로 Transaction처리를 하도록 하지만, Bean Management Transaction Model 이용하는 EJB, Servlet/JSP 등에서 종종 직접 트렌젝션을 처리하도록 하는 경우가 있다.

 

Java에서 직접 트렌젝션 프로그래밍을 경우에는 JDBC XA Interface 이용하는 방법과, JTA 이용하는 방법 크게 두가지가 있다. 방식의 가장 차이는 JDBC XA Interface 이용하면, Transaction 관리를 DBMS Transaction Manager, Application에서 담당해야하고, JTA 사용할 경우에는 Application Server Transaction Manager Transaction 관리를 하게 된다.

JDBC XA API Based Transaction Programming

 

JDBC XA API 사용하는 경우는  위에서도 언급했듯이, DBMS Transaction관리 기능을 이용해서, Application에서 직접 Transaction 관리하도록 프로그래밍을 한다.

 JDBC 2.0에서부터는 Global Transaction 프로그래밍을 위한 Interface, javax.sql.XAConnection, javax.sql.XADataSource Interface 제공한다. 말그대로, Java XA Interface 이용해서, XA Protocol 맞춰서, 프로그래밍을 하는것이다.

 

 아래는 Oracle JDBC XA Driver 이용해서, 2PC 구현한 예제이다.

 

import java.sql.*;

import javax.sql.*;

import java.util.*;

import oracle.jdbc.driver.*;

import oracle.jdbc.pool.*;

import oracle.jdbc.xa.OracleXid;

import oracle.jdbc.xa.OracleXAException;

import oracle.jdbc.xa.client.*;

import javax.transaction.xa.*;

import java.io.*;

 

class OracleXARun{

 

    // DB Connection Info

    final static String DB_FROM_ADDR = "127.0.0.1";

    final static int DB_FROM_PORT = 1521;

    final static String DB_FROM_SID = "ORCL";

    final static String DB_FROM_USER = "scott";

    final static String DB_FROM_PASSWORD= "tiger";

 

    // DB Connection Info

    final static String DB_TO_ADDR = "127.0.0.1";

    final static int DB_TO_PORT = 1521;

    final static String DB_TO_SID = "ORCL";

    final static String DB_TO_USER = "scott";

    final static String DB_TO_PASSWORD = "tiger";

 

    // main

    public static void main(String args[]){

          OracleXARun oxa = new OracleXARun();

 

          try{

          oxa.XARun();

          }catch(Exception e){

              e.printStackTrace();

          }

    }

 

    void XARun()

          throws XAException,SQLException

    {

          // step 1. open connection

          // step 1-1. create XA Data source (ResourceFactory)

          XADataSource xds1 = getXADataSource(DB_FROM_ADDR,DB_FROM_PORT

                       ,DB_FROM_SID,DB_FROM_USER,DB_FROM_PASSWORD);

          XADataSource xds2 = getXADataSource(DB_TO_ADDR,DB_TO_PORT

                       ,DB_TO_SID,DB_TO_USER,DB_TO_PASSWORD);

         

          // step 1-2. make XA connection (Transactional Resource)

          XAConnection xaconn1 = xds1.getXAConnection();

          XAConnection xaconn2 = xds2.getXAConnection();

         

          // step 1-3. make connection (DB Connecction)

          Connection conn1 = xaconn1.getConnection();

          Connection conn2 = xaconn2.getConnection();

         

          // step 2. get XA Resource (XAResource)

          XAResource xar1 = xaconn1.getXAResource();

          XAResource xar2 = xaconn2.getXAResource();

         

          // step 3. generate XID (Transaction ID)

          // 같은 Global Transaction ID 가지고, 다른 Branch Transaction ID

          // 갖는 Transaction ID 생성한다.

          Xid xid1 = createXid(1);

          Xid xid2 = createXid(2);

         

          // step 4. xa start (send XA_START message to XAResource)

          xar1.start(xid1,XAResource.TMNOFLAGS);

          xar2.start(xid2,XAResource.TMNOFLAGS);

         

          // step 5. execute query(execute Transaction)

          // FROM DB ACCOUNT계좌에서 1000원빼고, TODB ACCOUNTNO 1000이고 BALANCE 1000 레코드를

          // insert한다.

          String sql ;

                    

          Statement stmt1 = conn1.createStatement();

          sql = "update accountfrom set balance=balance-1000 where accountno=1000";

          stmt1.executeUpdate(sql);

 

          sql = " insert into accountto values(1000,1000)";

          Statement stmt2 = conn2.createStatement();

          stmt2.executeUpdate(sql);

         

          // step 6. xa end (Transaction 종료되었음을 알린다.)

          xar1.end(xid1,XAResource.TMSUCCESS);

          xar2.end(xid2,XAResource.TMSUCCESS);

         

          // step 7. xa prepare (xa prepare 한다.)

          int prep1 = xar1.prepare(xid1);

          int prep2 = xar2.prepare(xid2);

         

          // step 8. xa commit

          // step 8-1. check prepare stat

          // 양쪽다 prepare 성공하였으면 commit 준비를 한다.

          // XA_RDONLY update 없이 select등의 Read Only 있는 Transaction

          // 성공하였을때,

          boolean docommit=false;

          if( (prep1 == XAResource.XA_OK || prep1 == XAResource.XA_RDONLY)

                       && (prep2 == XAResource.XA_OK || prep2 == XAResource.XA_RDONLY) )

          {

              docommit = true;

          }

 

          if(docommit){

              // XA_RDONLY 이미 commit 되어 있기 때문에 따로 commit하지 않는다.

              if(prep1 == XAResource.XA_OK)

                       xar1.commit(xid1,false);

              if(prep2 == XAResource.XA_OK)

                       xar2.commit(xid2,false);

          }else{

              // roll back 하는 부분

              if(prep1 != XAResource.XA_RDONLY) xar1.rollback(xid1);

              if(prep2 != XAResource.XA_RDONLY) xar2.rollback(xid2);

          }

         

          // step 9. close connection

          conn1.close();

          conn2.close();

          xaconn1.close();

          xaconn2.close();

 

          conn1 = null;

          conn2 = null;

          xaconn1 = null;

          xaconn2 = null;

    }// XARun

 

    Xid createXid(int bids) throws XAException{

          byte[] gid = new byte[1]; gid[0] = (byte)9;

          byte[] bid = new byte[1]; bid[0] = (byte)bids;

          byte[] gtrid = new byte[64];

          byte[] bqual = new byte[64];

 

          System.arraycopy(gid,0,gtrid,0,1);

          System.arraycopy(bid,0,bqual,0,1);

 

          Xid xid = new OracleXid(0x1234,gtrid,bqual);

 

          return xid;

    }// createXid

 

    XADataSource getXADataSource(String dbAddr,int port,String sid

              ,String userId,String password)

          throws SQLException,XAException

    {

          OracleDataSource oxds = new OracleXADataSource();

          String url = "jdbc:oracle:thin:@127.0.0.1:1521:ORCL";

          oxds.setURL(url);

          oxds.setUser(userId);

          oxds.setPassword(password);

 

          return (XADataSource)oxds;

    }// getXADataSource

   

}// class OracleXARun

 

 

< 예제 Oracle JDBC XA Driver 이용한 2PC 구현 >

 

예제를 실행 하기 위해서 몇가지 준비가 필요하다.

 

1. 예제를 테스트한 환경은 하나의 데이타베이스에서 (하나의RM)에서 테스트를 했다. 먼저 첫번째 DB accountFrom이라는 테이블을 ,두번째 DB에는 accountTo 라는 이름의 테이블을 만들도록 하자.

 

 

// 첫번째 DB 만들어야할 테이블

CREATE TABLE ACCOUNTFROM(

        ACCOUNTNO NUMBER,

        BALANCE NUMBER,

        PRIMARY KEY(ACCOUNTNO)

);

INSERT INTO ACCOUNTFROM VALUES(1000,10000);

 

// 두번째 DB 만들어야할 테이블

CREATE TABLE ACCOUNTTO(

        ACCOUNTNO NUMBER,

        BALANCE NUMBER,

        PRIMARY KEY(ACCOUNTNO)

);

 

< Oracle JDBC XA Driver 실행하기 위한 데이타 베이스 테이블 >

 

2. final static으로, 선언되어 있는 첫번째 DB 두번째 DB 연결 정보를 알맞게 수정한다.

 

    final static String DB_XXXX_ADDR = "127.0.0.1"; // Oracle DB IP

    final static int DB_XXXX_PORT = 1521; // Oracle DB Port

    final static String DB_XXXX_SID = "ORCL"; // Oracle DB SID

    final static String DB_XXXX_USER = "scott"; // Oracle DB User ID

    final static String DB_XXXX_PASSWORD= "tiger"; // Oracle DB User Password

 

3. 컴파일하고 실행한다.

실행을하고 sqlplus 이용해서 accountfrom accountto select 해보면, accountfrom에는 accountno 1000 row balance 1000 빠졌을것이고, accountto 테이블에는 accountno1000이고, balance 1000 row 생성되었을 것이다.

 

다시 실행을 해보면, accountto 테이블에 이미 accountno 1000 row 있기 때문에, 무결성 제약조건에 의해서 오라클 에러를 출력하고, 트렌젝션을 rollback하게 된다.

   

지금까지, JDBC XA Interface 이용해서 2PC 구현하는것과, JAVA에서의 Transaction처리 과정에 대해서 살펴보았다. 쉽지는 않은 내용이지만, 내용을 알아놓으면, 나중에 복잡한 트렌젝션 프로그래밍을 할대 도움이 될것이다.

JTA Based Transaction Programming

 

다음으로는 JTA Interface 이용해서 실제 Transaction 프로그래밍을 하는 과정을 알아보자. 보통 EJB 일반 애플리케이션에서 Web Application Server(WAS)등의 Transaction Manager등을 이용해서 Transaction 관리를 할때, JTA 이용해서 프로그래밍을 한다.

 

Transaction Manager 있을때에는 특정한 목적이 아니라면, 굳이 직접 XA 인터페이스를 사용해서 프로그래밍을 필요없이, JTA 사용하면 보다 쉽게 Transaction 프로그래밍을 있다.

 

JTA 프로그래밍을 하기 위한 기본적인 순서를 살펴보면

 

1.       User Transaction 객체(tx) 얻어온다.

2.       얻어온 User Transaction 객체 tx 이용하여, User Transaction 시작한다. tx.begin();

3.       각각의 Resource (DBMS,JMS) 연결을 한후, 각각의 쿼리등의 작업을 수행한다.

Resource들과 연결할때 주의해야할 사항이 몇가지가 있다. 일단 Resource Adapter XA 지원해야 한다. Oracle 경우, JDBC Driver oracle.jdbc.driver.OracleDriver 아니라, oracle.jdbc.xa.client.OracleXADataSoruce 사용해야한다.

 

데이타베이스 Connection (java.sql.conn) 얻어올때에도 DriverManager.getConnection 이용하는것이 아니라, WAS 의해서 관리되는 Resource Factory 통해서 얻어와야된다. DBMS 경우에는 DataSource등을 통해서 Connection 얻어오게 된다.

 

4.       만약 에러가 발생했으면 tx.rollback();으로 전체 트렌젝션을 roll back시킨다.

5.       정상적으로 트렌젝션이 완료 되었을경우에는 tx.commit(); 으로 전체 트렌젝션을 commit한다.

 

그럼 간단한 예제를 만들어보기로 하자.

 

예제는 앞에서 만들었던 내용과 똑같이 하나의 DBMS ACCOUNTFROM이라는 테이블에서 ACCOUNTNO 1000 레코드의 BALANCE값을 1000 감소시키고, ACCOUNTTO라는 테이블에 ACCOUNTNO 1000, BALANCE 1000 ROW INSERT하는 내용이다.

 

이전 예제와 같이 각각의 DBMS ACCOUNTFROM, ACCOUNTTO라는 테이블을 생성하자.

 

생성이 끝났으면 WebLogic 설정하자

 

1.       JDBC Connection Pool 설정한다.

 

웹로직을 실행하고, 웹로직 CONSOLE 접속한다. (http://localhost:7001/console)

좌측 네비게이션 트리에서, Services  > JDBC >ConnectionPools 선택하고, Configure a new JDBC Connection Pool 선택한다.

 

Configure>General Tab에서

Name : OracleXAPool

URL : jdbc:oracle:thin:@127.0.0.1:1521:ORCL (각자 환경에 맞게 변경)

Driver Classname: oracle.jdbc.xa.client.OracleXADataSource (일반 JDBC 드라이버랑 다르기 때문에 주의!!)

Properties :

user=scott

password=tiger

 

입력한후, Targets Tab에서 해당 서버에 Targetting 한다.

 

2.       TXDataSource 설정한다.

 

좌측 네비게이션 트리에서, Services  > JDBC >TX Data Sources 선택하고, Configure a new JDBC TX Data Source 선택한다.

일반 DataSource 사용하는것이 아니라, 웹로직의 경우에는 global transaction 사용하기 위해서, TX DataSource 사용한다.

 

Configuration 탭에서 내용을 입력한다.

Name : OracleTXDS

JNDI Name : OracleTXDS

PoolName : OracleXAPool (앞에서 지정한 이름)

 

생성된 TX Data Source Target Tab에서 해당 서버로 지정한다.

 

 

 

<%@ page contentType="text/html;charset=euc-kr"

          import="javax.naming.*

                       ,javax.transaction.*

                       ,java.sql.*

                       ,javax.sql.*

                       ,java.util.*"

%>

<%!

 

 

  // DB Connection Info

  final static String DB_FROM_DATASOURCE="OracleTXDS";

  final static String DB_TO_DATASOURCE="OracleTXDS";

  //final static String DB_TO_DATASOURCE="OracleTXDS_Chaeju";

 

  void JTARun()

    throws Exception

  {

 

    // step 1. JNDI Lookup and get UserTransaction Object

    Context ctx = null;

    Hashtable env = new Hashtable();

 

    // Parameter for weblogic

    env.put(Context.INITIAL_CONTEXT_FACTORY,

                       "weblogic.jndi.WLInitialContextFactory");

    env.put(Context.PROVIDER_URL,"t3://localhost:7001");

    env.put(Context.SECURITY_PRINCIPAL,"system");

    env.put(Context.SECURITY_CREDENTIALS,"weblogic");

 

    ctx = new InitialContext(env);

    System.out.println("Context Created :"+ctx);

 

    // step 2. get User Transaction Object

    UserTransaction tx = (UserTransaction)

                                 ctx.lookup("javax.transaction.UserTransaction");

    // step 3 start Transaction

    System.out.println("Start Transaction :"+tx);

    tx.begin();

 

    try{

    // step 4. doing query

      // step 4-1. get Datasource

      DataSource xads1 = (DataSource)ctx.lookup(DB_FROM_DATASOURCE);

      DataSource xads2 = (DataSource)ctx.lookup(DB_TO_DATASOURCE);

 

      System.out.println("Datasource from :"+xads1);

      System.out.println("Datasource to :"+xads2);

 

      // step 4-2. get Connection

      Connection conn1 = xads1.getConnection();

      Connection conn2 = xads2.getConnection();

 

      conn1.setAutoCommit(false);

      conn2.setAutoCommit(false);

 

      System.out.println("Connection from :"+conn1);

      System.out.println("Connection to :"+conn2);

 

      // step 4-3 execute query

      Statement stmt1 = conn1.createStatement();

      String sql = "update accountfrom set balance=balance-1000 where accountno=1000";

      stmt1.executeUpdate(sql);

      System.out.println("Statement 1 passed ");

     

      Statement stmt2 = conn2.createStatement();

      sql = "insert into accountto values(1000,1000)";

      stmt2.executeUpdate(sql);

      System.out.println("Statement 2 passed ");

 

      // step 4-4. close connection

      stmt1.close();

      conn1.close();

 

      stmt2.close();

      conn2.close();

      

      System.out.println("connection closed  ");

      System.out.println("tx :"+tx);

 

      tx.commit();

      System.out.println("Transaction Commited");

    }catch(Exception e){

      System.out.println("Transaction rolled back due to :"+e);

      tx.rollback();

    }// try-catch

    System.out.println("End Transaction ");

 

    ctx.close();

  }// JTARun

 

%>

<%

          JTARun();

%>

 

< 예제, WebLogic 이용한 JTA User Transaction 2PC 구현 >

 

실행결과는 웹로직 콘솔에 나타난다. (WINDOWS 경우에는 DOS창이나 로그에.)

 

Context Created :javax.naming.InitialContext@585571

Start Transaction :ClientTM[myserver+10.136.0.133:7001+mydomain+]

Datasource from :weblogic.jdbc.common.internal.RmiDataSource@334bd3

Datasource to :weblogic.jdbc.common.internal.RmiDataSource@334bd3

Connection from :weblogic.jdbc.rmi.SerialConnection@1b12fb

Connection to :weblogic.jdbc.rmi.SerialConnection@7b3d5c

Statement 1 passed

Statement 2 passed

connection closed

tx :ClientTM[myserver+10.136.0.133:7001+mydomain+]

Transaction Commited

    End Transaction

 

< 정상적인 처리 결과 >

 

No comments: