자바스터디 네트워크 [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 테이블에는 accountno가1000이고, 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:
Post a Comment