SSISO Community

시소당

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

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

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

 

 

실제로 IT 시스템을 구현함에 있어서 트렌젝션처럼 필수적인 요소도 없으리라 생각된다. 특히 금융권이나, 데이타의 정확성등이 요구되는 비지니스 업무에서는 트렌젝션 지원이 필수적인 요소로 대두 되고, 좀더 안정적이고, 빠른 트렌젝션 처리를 위해서, 많은 미들웨어 들이 사용되고 있다.

 

그러나,실제로 프로그래밍을 하는데 있어서, 제대로 트렌젝션 프로그래밍을 하는 개발자는 그리 많지 않다물론 많은 미들웨어가 트렌젝션에 관련된 많은 작업을 수행해주지만, 절대로 미들웨어는 만능이 아니다. 정확한 트렌젝션의 개념을 알고, 거기에 맞는 프로그래밍을 해야만 제대로 트렌젝션을 보장 받을 있다

 

 이번호 부터 3회에 걸쳐서, 트렌젝션에 대해서 알아보고, 트렌젝션을 자동적으로 관리해주는 미들웨어와, 그리고, 실제로 JAVA 기반에서 XA 인터페이스를 이용하거나 EJB 이용하여 트렌젝션을 프로그래밍하는 방법에 대해서 알아보도록 하자.

 

이번호는 첫시간으로, 먼저 트렌젝션이 무엇인지 그리고 분산 트렌젝션은 어떤식으로 처리되는지 트렌젝션 관리는 어떻게 되는지, 그리고 마지막으로 트렌젝션의 격리 레벨에 대해서 살펴보도록 한다.. 결코 쉬운 내용은 아니지만 적어도 데이타 베이스 프로그래밍을 하는 개발자라면 필히 알고 있어야하는 내용이다.

1.   트렌젝션이란 무엇인가? (What is transaction ?)

 

트렌젝션이란, 중단없이 시작에서부터 종료까지 한번에 수행되어야 하는 하나의 작업단위를 이야기한다. 수행이 끝난후에는 중간에 작업이 실패되었을 경우에는 작업 수행전의 상태로 그대로 돌아가야 한다.

 

이해를 돕기위해서 쉽게 예를 들어서 설명하도록 하자, A계좌에서 B계좌로 1,000원을 계좌 이체를 한다고 가정하자. 작업은 다음과 같은 순서로 이루어지게 된다.

 

1)       A계좌에서 1,000원을 인출한다.

2)       B 계좌에 1,000원을 더한다.

 

만약 위의 작업을 수행하던 도중 A계좌에서 1,000원이 인출된 후에, 은행 시스템의 오류로 인해서 B계좌에 1,000원이 더해지지 않는다면, 중간에 1,000원이라는 돈은 공중에서 증발해 버린것이 된다. 이럴때는 다시 계좌이체를 수행하기 이전의 상태로 되돌려서 A계좌에로부터 1,000원을 인출하지 말아야 한다.

 

그래서 위의 1),2) 작업은 한꺼번에 이루어져야 한다. 계좌이체 작업과 같이 한번에 이루어져야 하는 작업을 트렌젝션이라고 부른다.

 

이처럼 트렌젝션은 쇼핑몰의 주문 결제나,예매와 같이 Mission Critical 작업 있어서 필수적인 개념이라고 있다.

2.   트렌젝션의 기본속성 ACID (Transaction attribute “ACID” )

 

트렌젝션은 크게 4가지 특성을 가지는데 Atomicity,Consistency,Isolation,Durability, 네가지를 줄여서 ACID라고 부른다.

그럼 이제 부터 ACID속성 각각에 대해서 상세하게 알아보도록 하자.

 

Atomicity (원자성)

Database modifications must follow an all or nothing.

원자성이란, 하나의 트렌젝션이 하나의 단위로만 처리가 되어야 한다는것이다. 하나의 트렌젝션안에 여러가지 step 트렌젝션이, 하나로 처리가 되어야한다. 위의 계좌 이체처럼, 계좌에서 돈을 빼고, 돈을 다른 계좌에 넣는 것과 같이 두개이상의 step으로 구성되어 있더라도, 계좌 이체라는 하나의 트렌젝션으로 처리가 된다.

 그래서, 어느 step에서라도 트렌젝션이 실패가 되었을 경우에는 모든 상태가 트렌젝션 상태 전으로 rolled back되서, 이전 상태를 유지해야 한다.

  트렌젝션의 원자성은 트렌젝션이 완전히 수행되거나, 아무것도 수행되지 않은 All or Nothing 이미를 가지게 된다.

Consistency (일관성)

states that only valid data will be written to the database

트렌젝션이 종료된후에 저장되는 데이타는 오류없는 데이타만 저장되어야 한다.

 다시 풀어서 이야기하자면 계좌이체 과정에서, 인출은 되었는데, 다른 계좌로 돈이 안넘어갔다던지, 트렌젝션이 끝난후에, 잘못된 데이타 값으로 변경되었던지, 데이타베이스 constraint 깨졌던지 했을때, Consistency 잘못되었다고 이야기하고, 이런경우에 트렌젝션 내용을 저장하지 말고, 이전 상태로rollback되어야 한다.

Isolation (격리성)

Multiple transactions occurring at the same time not impact each other execution

격리성이란, 트렌젝션중에 의해서 변경된 내용이 트렌젝션이 완료되기전까지는 다른 트렌젝션에 영향을 주어서는 안된다는 이야기이다.

Tx A라는 트렌젝션 수행중 EMP 테이블의 값을 변경했을때, Tx A 완료되지 않은 상태에서 Tx B EMP 테이블의 값을 참고할 경우에, Tx A 의해 변경된 값을 참고하는것이 아니라(아직 TxA 완료되지 않았기 때문에) 기존의 값을 참고하게 해야한다.

Durability (지속성)

Ensures that any transaction committed to the database will not be lost.

지속성이랑, 트렌젝션이 완료된후에의 값이 영구저장소에 제대로 기록이 되어야한다는 의미이다. 트렌젝션이 완료되었는데, 디스크 IO에러,네트워크 등으로 값이 제대로 기록이되지 않거나 해서는 안된다는 이야기다.

 

3.   분산 트렌젝션 (Distributed Transaction or Global Transaction)

 

Transaction in source code

 

그러면, 일반적으로 프로그래밍 코드 상에서, 트렌젝션을 사용하는 방법에 대해서 알아보도록하자.

 

 

Begin Transaction

// Do transaction

 

if(error) then roll back

 

  Prepare Transaction.

if (prepare transaction failed) then rollback

else Commit Transaction

 

End Transaction

 

 

 

일반적인 트렌젝션 프로그램은 위와 같은 코드 구조를 가지고 있다.

먼저 Begin Transaction 시작하면, 여기부터가 하나의 Transaction임을 알리는 boundary 역할을 한다.

 // Do transaction 부분에서 Transaction 대한 실질적인 트렌젝션 처리 코드가 들어간다.

(SQL문장등등..)

 

If(error) then roll back :트렌젝션 처리중에 에러가 발생하면, rollback 실행해서, 트렌젝션 수행전 상태로 되돌린다. 트렌젝션에 대한 처리가 끝나면, Prepare Transaction 실행해서, commit 가능한지 각각의 트렌젝션 대상 (Resource Manager, DBMS 같은..) 체크를 한다.

 

If(prepare transaction faield) then rollback

Else Commit Transaction

 

Commit 될준비가 됐으면 commit 실행하고, 아닌경우에는 rollback 한다.

모든 트렌젝션이 완료되었으면 End Transaction으로 트렌젝션을 종료한다.

 

언뜻 보기에 당연하고 단순한 과정으로 보일 있으나, 이는 Transaction 처리하는 대부분의 미들웨어에서 공통적으로 사용하는 방법이니, 머리속에 익혀두도록 하자. J2EE EJB에서의 트렌젝션은 대부분 이런 트렌젝션의 처리 과정을 EJB Container에서 자동으로 처리해주기 때문에(CMT : Container Managed Transaction Model)  실질적으로 개발자가, 직접적으로 트렌젝션을 Handling할일은 그렇게 많지는 않다.

 

Distributed Transaction and XA

 

그러면 이제 미들웨어의 핵심 기능이라고할 있는 분산 트렌젝션(Distributed transaction, or Global transaction이라고도 한다.) 대해서 알아보도록 하자.

 

분산 트렌젝션이란,  두개 이상의 Resource (RDBMS등등) 이용해서 하나의 트렌젝션으로 처리하는것이 이야기 한다. 분산 트렌젝션을 수행하기 위한 시스템의 구조를 잠깐 살펴보도록 하자.

 

 

Transsaction

Manager

(TM)

RM

Resource Manager

(RM)

DB1

DB2

XA

javax.transaction.xa.XAResource

javax.transaction.TransactionManager

Application (AP)

 

 

 

 

 

 

 

 

 

 

 

 


< 그림 1. 분산 트렌젝션을 수행하기 위한 미들웨어의 대략적 구조 >

 

분산 트렌젝션을 구성하는 구조에는 크게 3가지 요소가 결합된다. AP,TM,RM이다.

 

Application

각각을 알아보면, AP Application, User 트렌젝션을 발생시키고 프로그래밍 하는 부분을 말한다. 우리가 개발하게될 부분은 이부분이며, J2EE EJB 이용한 분산 트렌젝션의 경우에는 Web Application Server (이하 WAS) 이역할을 자동으로 해결해주게 된다.

 

Resource Manager

다음으로는 RM Resource Manager, 각각의 Resource 컨트롤 해주는 기능을 갖는다. JAVA에서는 일종의 JDBC 드라이버와 같은 기능을 한다고 생각하면되고, 실제로 RM 기능을 하는 모듈은 DBMS Vendor에서 JDBC드라이버 패키지에 넣어서 배포하도록 되어 있다. 단순히 RDBMS 아니라, RM 가지고 있는 Resource로는 XA 지원하는 ISAM,JMS 같은 메시징 시스템에서 부터 상당히 많은 종류가 있다.

 

Transaction Manager

마지막으로  TM Transaction Manager 약자로, 전체 분산 트렌젝션을 관리해주는 역할을 한다. WAS 기능이 내장되어 있다.

 

XA eXtended Architecture Open Group 의해서 정의되었으며, Global Transaction 관리하기 위한 귀약과, RM TM사이의 프로토콜을 정의하고 있다.

 

그러면 어떻게 트렌젝션이 수행이 되는지, 대략적인 시나리오를 한번 살펴보도록 하자.

아래와 같은 트렌젝션 수행 코드가 있다고 하자.

 

 

Begin Transaction

 Xid = get new transation id

 doTransaction(Xid,RM1)

 doTransaction(Xid,RM2)

 

 commitTransaction(Xid)

End Transaction

 

 

Begin Transaction

 Xid = get new transaction id

 

먼저 트렌젝션이 수행되면, 트렌젝션에 대한 Global Transaction Id Xid 생성이 된다.

그리고, DB1 DB2 각각 연결되어 있는 RM1 RM2 연결되어 있을때,

 

doTransaction(Xid,RM1)

doTransaction(Xid,RM1)

 

AP 직접 RM 통해서 DB작업을 실행한다.

 이때 Xid 같이 RM에게 보내서 지금 실행되는 작업이 어떤 트렌젝션에 관련된 작업인지를 식별할 있게 해준다.  물론, 작업중에, error 발생했을경우에는 roll back 수행한다. 여기까지 작업이 종료되면,

 

commitTransaction(Xid)

 

하게 되는데. 작업은 TM RM간의 작업이다. TM RM1,RM2에게 commit 준비가 되었는지를 각각의 RM 물어서 체크를 한다. 이때 RM 동시에 여러개의 Transaction 수행중일 있다. (RDBMS 한번에 하나의 트렌젝션만 처리 하고 있지는 않다. 당연히 여러개의 트렌젝션을 처리하고 있다. ) 그래서, 어떤 트렌젝션을 체크할것인지를 구별하기 위해서, TM RM에게 Xid 실어서 보낸다.  이렇게 TM RM에게 Xid 식별된 트렌젝션이 commit 준비가 되었는지를 묻는 과정을 prepare라고 한다.

 

Prepare 되었으면 TM RM에게 commit 하도록 지시 한다. 만약 prepare 실패하면 TM RM에게 rollback 지시한다.

 

이렇게 prepare과정과 commit과정 두단계를 거치는 것을 two phase commit (2pc)라고 한다. 분산 트렌젝션에서 많이 나오는 개념이니까는 알아두도록 하자.

 

EndTransaction

트렌젝션을 종료하고, 내용을 반영한다.

 

지금까지 살펴본 내용은 분산 트렌젝션의 아주 일반적인 작동원리를 살펴보았다. (실제로 XA프로토콜을 이용해서, 분산 트렌젝션을 처리하는 과정은 이보다 좀더 복잡하다. 자세한 사항은 XA 관련 Spec이나, Transaction 관련 서적을 참고하기 바란다.)

 

4.   트렌젝션 분리 레벨(Transaction Isolation Level )

 

데이타베이스 환경에서는 일반적으로 Single User 아니라 Multi User 환경을 지원하기 때문에, 여러명은 동시에 같은 데이타를 읽거나 insert/update하는 일이 생긴다. 과정에서, 데이타의 일관성(Consistency) 동시성(Concurrency) 보장해줘야한다.

 

Data Consistency데이타 일관성은,  어느 사용자가 데이타를 ACCESS 하던지, 같은 내용의 데이타를 있는 속성

Data Concurrency 데이타 동시성은 , 동시에 여러 사용자가 같은 데이타를 ACCESS 있는 속성

 

일반적으로 데이타 베이스는 여러개의 트렌젝션을 하나씩 순차적으로 처리(serially) 하는것이 아니라 동시에 여러 트렌젝션을 처리한다. 과정에서 동시에 처리되는 트렌젝션간의 변경된 데이타를 각각 어떻게 적용할 것인가에 대한 규칙이 Transaction Isolation Level이다.

 

예를 들어 설명해보자.

 

1)       트렌젝션 TX_A 시작 되었고, 동시에 트렌젝션 TX_B 시작되었다.

2)       TX_A에서 SELECT NAME FROM TABLE_A WHERE  ID=1 수행하였다. 결과는 ORIGIN 나왔다고 가정하자.

3)       TX_B에서 UPDATE TABLE_A SET NAME=”CHANGED” WHERE ID =1

4)       TX_A에서 다시 SELECT NAME FROM TABLE_A WHERE  ID=1 수행하였다.

5)       TX_B COMMIT하였다.

6)       TX_A에서 다시 SELECT NAME FROM TABLE_A WHERE  ID=1 수행하였다.

 

이런 과정을 거쳤을때, 4)에는 CHANGED 나올까? 아니면 ORIGIN 나올까? 6)에서도 CHANGED 나올까 ORIGIN 나올까? 어떤 트렌젝션이 데이타를 변경하였을때 같은 데이타를 억세스하는 트렌젝션에 대해서 어떤 영향을 미치느냐를 정하는 규칙(Isolation Level) 따라서 나올 있는 결과가 틀리게 된다.

 

Preventable Phenomena

 

서로 다른 트렌젝션에 어떻게 영향을 주느냐에 따라서 3가지 Preventable Phenomena 나뉘어 지는데.. 내용을 살펴보자.

 

Dirty Read

어떤 트렌젝션이 데이타를 변경하고, COMMIT 하지 않았을때도, 다른 트렌젝션에서 값을 읽으면 변경된 값이 반영되는 경우이다.

1)       TX_A 시작되고, SELECT NAME FROM TABLE_A WHERE ID=1에서 ORIGIN 출력되었다고 가정하자.

2)       TX_B에서 UPDATE TABLE_A SET NAME=”CHANGED” WHERE ID =1 실행한후

3)       TX_A 시작되고, SELECT NAME FROM TABLE_A WHERE ID=1에서 CHANGED 출력된다.

2)에서 UPDATE 내용을 COMMIT하지 않았는데도 반영이 되면 이를 Dirty Read라고 한다.

 

NonRepeatable Read (Fuzzy Read)

어떤 트렌젝션이 데이타를 변경 (update delete 해당됨)하고, COMMIT 하면, COMMIT 내용은 다른 트렌젝션에 반영된다.insert 내용은 반영되지 않는다.

 

1)       TX_A 시작되고, SELECT NAME FROM TABLE_A WHERE ID=1에서 ORIGIN 출력되었다고 가정하자.

2)       TX_B에서 UPDATE TABLE_A SET NAME=”CHANGED” WHERE ID =1 실행한후

3)       TX_A에서 SELECT NAME FROM TABLE_A WHERE ID=1하면 ORIGIN 출력된다.

4)       TX_B COMMIT한후

5)       SELECT NAME FROM TABLE_A WHERE ID=1하면 CHAGNED 출력된다.

 

Phantom Read

 

어떤 트렌젝션이 새로운 데이트를 삽입(Insert)하고, COMMIT하면, COMMIT 내용은 다른 트렌젝션에 반영된다. (NonRepeatable read 같으나, NonRepetable update,delete, Phantom Read insert 내용이 반영된다.)

 

1)       TX_A 시작되고, SELECT COUNT(*) FROM TABLE_A WHERE GRP=1에서 10 출력되었다고 가정하자.

2)       TX_B에서  INSERT INTO TABLE_A (ID,GRP) VALUES(100,1);

3)       TX_A에서  SELECT COUNT(*) FROM TABLE_A WHERE GRP=1하면 10 출력된다.

4)       TX_B COMMIT한후

5)        TX_A에서  SELECT COUNT(*) FROM TABLE_A WHERE GRP=1하면 11 출력된다

Isolation Level

 

ANSI/ISO SQL 표준 (SQL92)에서는 4가지 Isolation Level 지원하는데. 내용은 간단하게 다음과 같은 표로 정리된다.

Isolation Level

Dirty Read

NonRepetable Read

Phantom Read

Read uncommitted

Possible

Possible

Possible

Read committed

Not Possible

Possible

Possible

Repetable read

Not Possible

Not Possible

Possible

Serializable

Not Possible

Not Possible

Not Possible

 

How to setup Oracle and Java Isolation Level

 

많이 사용하고있는 Oracle DBMS 경우에는 Default Read Commited 설정이 되어 있으며, Oracle 9(현재)까지, Isolation Level Read commited, Serializable 두가지만 지원하고 있다.

 

Oracle에서 Isolation Level 변경하는 방법은 SQL PLUS에서 LEVEL 따라서 다음과 같은 명령어를 치면된다.

 

SET TRANSACTION  ISOLATION LEVEL READ COMMITED;

SET TRANSACTION  ISOLATION LEVEL SERIALIZABLE;

 

JAVA에서도 데이타베이스 Isolation Level 따라 알맞은 Isolation Level 지정해 줘야하는데, 방법은 다음과 같다.

 

 Connection conn = DriverManager.getConnection(url, uid, pwd);

 conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);

 System.out.println(conn.getTransactionIsolation());

 

지금까지 간단하게 Isolation Level 대해서 살펴보았다.. 트렌젝션에 관련된 내용이고 심심지않게 언급되는 내용이라서 간단하게 정리해보았다. 좀더 자세한 내용은 Oracle 홈페이지에서 Oracle 8i Concepts Release 8.1.5 A67781-01 문서의 27 Data Concurrency and Consistency 부분을 살펴보기 바란다.

 

 

지금까지 대략적인 트렌젝션에 대한 개념과, 어떤식으로 트렌젝션이 처리되는지, 그리고, 트렌젝션 격리 레벨에 대해서 알아보았다. 그럼 다음호에서는 JAVA에서의 트렌젝션 프로그래밍 JTA,JTS 그리고 JDBC XA 드라이버를 이용한 분산 트렌젝션 프로그래밍에 대해서 알아보도록 한다.

1444 view

4.0 stars