EJB CMT 방식의 2PC XADatasource처리방식

EJB CMT 방식의 2PC XADatasource처리방식


이제는 EJB는 구현된 프로젝트를 찾기 힘들만큼 오래된 기술이 되어버렸다. 하지만 현재 회사에서 사용하는 프레임워크가 EJB방식으로 트랜젝션 처리를 하기 때문에 EJB방식의 트랜젝션 처리과정을 정리한다.


J2EE스펙을 지원하는 WAS사용

우선, EJB를 사용하기 위해서는 반드시 JEUS, JBOSS, WEBLOGIC등 J2EE 스펙을 지원하는 미들웨어를 사용해야한다. J2EE스펙을 지원하는 미들웨어는 EJB Been을 관리해주는 EJB컨테이너가 존재하지만, 그렇지 않은 Tomcat같은 경우는 웹컨테이너만 제공하기 때문에 J2EE를 지원할 수 없다. 


WAS ConnectionPool을 이용한 DataSource등록

EJB에서 사용될 DataSource는 WAS제공하는 ConnectionPool에 등록되어야 한다. EJB는 필요한 시점에 ConnectionPool에서 DataSource를 JNDI방식으로 LookUp하여 획득하는 방식으로 사용한다. 이는 EJB에서 직접 TransactionManager를 구현하지 않고, WAS벤더사에서 구현한 JTA (Java Transaction API)를 사용하기 위함이다. 로컬방식의 DBCP를 사용하는 경우 서버 TranscationManager가 이를 조작할 수 없다.


서버 트랜젝션 매니저

JEUS는 서버 트랜잭션 매니저와 클라이언트 트랜잭션 매니저의 두 가지 트랜잭션 매니저를 제공한다.

서버 트랜잭션 매니저는 글로벌 트랜잭션을 관리하기 위한 모든 기능을 제공한다. 반면에 클라이언트 트랜잭션 매니저는 서버 트랜잭션의 대행(proxy) 역할만을 수행한다.


서버 트랜잭션 매니저는 Java Transaction API를 모두 구현했으며, 서버 애플리케이션이 트랜잭션을 사용할 경우 동작한다.

글로벌 트랜잭션이 시작되면 서버 트랜잭션 매니저는 글로벌 트랜잭션과 관련된 모든 정보를 수집해서, 트랜잭션의 Coordinator로서 작업을 진행한다. 상황에 따라서 Root CoordinatorSub Coordinator로 역할이 나뉜다.


  • Root Coordinator

    • 트랜잭션이 시작되는 트랜잭션 매니저가 담당하며, 여기서 시작된 트랜잭션이 전파되는 매니저는 Sub Coordinator가 된다.

  • Sub Coordinator

    • Root Coordinator로부터 결정을 받아 해당하는 작업을 수행한다. 즉, 능동적으로 트랜잭션을 관리하는 역할이 Root Coordinator, 이 내용을 따라하는 수동적 역할이 Sub Coordinator가 할 일이다.


■ EJB BEEN 관리 방식의 BMT 트랜젝션 처리

Bean 관리 트랜잭션은 웹 컨테이너와 EJB 컨테이너에서 애플리케이션은 JTA를 사용해서 글로벌 트랜잭션 경계를 정할 수 있다. 애플리케이션이 글로벌 트랜잭션을 세밀하게 조절할 필요가 있을 때 유용한다. 실행 순서에 따라 클라이언트의 요청을 처리할 수 있기 때문에 애플리케이션은 자신의 판단에 따라서 commit과 rollback을 할 수 있다.


다음은 EJB 컨테이너에서 애플리케이션이 글로벌 트랜잭션을 실행하는 예제이다.


package bmt;


import javax.ejb.*;

import javax.naming.*;

import java.sql.*;

import java.util.*;

import javax.annotation.*;

import javax.transaction.UserTransaction;


@Stateless

@TransactionManagement(TransactionManagementType.BEAN) 

public class ProductManagerEJB implements ProductManager {

    @Resource SessionContext ejbContext;   


    public void transactionTest() {

        UserTransaction tx = null;

        try {

          int number = 20;

          String products[] = new String[number];

          tx = ejbContext.getUserTransaction();

          tx.begin();

          // insert products

          for (int i=0 ; i<number/2 ; i++) {

               System.out.println("inserting product id="+i+"b ...");

               products[i] = insertProduct(i+"b", "ball pen", i*10);

           }

           for (int i=number/2 ; i<number ; i++) {

               System.out.println("inserting product id="+i+"f...");

               products[i] = insertProduct(i+"f", "fountain pen", 

               (i-number/3)*50);

           }

           System.out.println("completed inserting products!!");

            // delete products

           for (int i=0 ; i<number ; i++) {

               System.out.println("deleting product id="+products[i]+" ...");

               deleteProduct(products[i]);

           }

           System.out.println("completed deleting products!!");

           tx.commit();

        } catch (javax.transaction.SystemException se) {

            throw new EJBException(

                "Transaction System Error caught : " + se.getMessage());

        } catch (javax.transaction.RollbackException re) {

            throw new EJBException(

                "Transaction Rollback Error caught : " + re.getMessage());

        } catch(Exception e) {

           try {

              tx.rollback();

           } catch (Exception ee) {

              throw new EJBException("Transaction Rollback error : " + ee.getMessage());

           }

           throw new EJBException("Error caught : " + e.getMessage());

        }

    }


    private String insertProduct(String id, String name, double price) 

        throws NamingException, SQLException {

        // insert a product entity given by the arguments to DB

    }


    private void deleteProduct(String id) throws NamingException,SQLException {

        // delete a product entity indicated by the argument from

        // DB

    }

    // some EJB callback methods

}

EJB 컨테이너 관리 트랜잭션(CMT - Container Managed Transaction)

Java EE 스펙에 의하면 애플리케이션은 글로벌 트랜잭션 경계(demarcation) 지정을 컨테이너에 위임할 수 있다. 웹 컨테이너나 EJB 컨테이너는 메소드와 관련된 글로벌 트랜잭션을 관리한다. 애플리케이션은 설정 파일에 메소드별로 트랜잭션 속성을 정할 수 있다. 이 방법은 글로벌 트랜잭션을 처리하는 가장 쉬운 방법이다.


package cmt;


import javax.ejb.*;

import javax.naming.*;

import java.sql.*;

import java.util.*;

import javax.annotation.*;


@Stateless

@TransactionManagement(TransactionManagementType.CONTAINER) 

public class ProductManagerEJB implements ProductManager {

    public void transactionTest() {

      try {

          int number = 20;

          String products[] = new String[number];

          // insert products

          for (int i=0 ; i<number/2 ; i++) {

              System.out.println("inserting product id="+i+"b...");

              products[i] = insertProduct(i+"b", "ball pen", i*10);

          }

          for (int i=number/2 ; i<number ; i++) {

          System.out.println("inserting product id="+i+"f...");

          products[i] = insertProduct(i+"f", "fountain pen", (i-number/3)*50);

      }

      System.out.println("completed inserting products!!");

      // delete products

      for (int i=0 ; i<number ; i++) {

        System.out.println("deleting product id="+products[i]+" ...");

        deleteProduct(products[i]);

      }

      System.out.println("completed deleting products!!");

     } catch(Exception e) {

       throw new EJBException("Error caught : " +  e.getMessage());

     }

  }


    private String insertProduct(String id, String name, double price) 

        throws NamingException, SQLException {

        // insert a product entity given by the arguments to DB

    }


    private void deleteProduct(String id) throws NamingException, SQLException {

        // delete a product entity indicated by the argument from

        // DB

    }


    // some EJB callback methods

}


위에 소스중 DataSource와 DB조작은 생략된 부분이 많은데, 이때 메소드 단위로 트랜젝션 전파속성을 지정할 수 있다. JTA 스펙을 구현한 서버 트랜젝션 매니저는 CMT방식의 선언적 트랜젝션관리를 통해서 트랜젝션을 처리하게된다.


@TransactionAttribute(TransactionAttributeType.REQUIRED)

public void addBook(Book book) throws CMTException {

Connection conn = null;

PreparedStatement psmt = null;

try {

conn = ds.getConnection();

String sql = "INSERT INTO BOOK (...) VALUES(...)";

... 생략

} catch (Exception e) {

ctx.setRollbackOnly(); // 트랜잭션을 롤백한다. CMT에서만 지원

throw new CMTException("예외가 발생했습니다.", e);

} finally {

// 관련 자원을 해제한다.

close(psmt, conn);

}

}


 EJB 트랜젝션 전파속성

TransactionAttributeType.REQUIRED

  • 기본 트랜잭션 속성
  • 무조건 트랜잭션 처리

TransactionAttributeType.REQUIRES_NEW 

  • 빈 메소드를 호출하면 항상 새로운 트랜잭션으로 처리

TransactionAttributeType.SUPPORTS

  • 트랜잭션 지원을 명시
  • 이미 트랜잭션이 시작된 상황에서 이 메소드를 호출하면 계속 처리
  • 트랜잭션이 시작되지 않은 상황에서 이 메소드를 호출하면 그래도 계속 처리
  • 트랜잭션을 지원한다는 의미

TransactionAttributeType.NOT_SUPPORTED

  • 트랜잭션을 지원하지 않음을 명시
  • 트랜잭션이 시작된 상황에서 이 속성으로 명시된 빈 메소드를 호출하면 트랜잭션이 일시중지됨

TransactionAttributeType.MANDATORY

  • 반드시 트랜잭션으로 처리함을 명시
  • 특정 메소드가 이 속성을 되어 있지만 트랜잭션 처리가 되지 않으면 예외발생

TransactionAttributeType.NEVER

  • 절대로 트랜잭션으로 처리해서는 안됨을 명시
  • 트랜잭션이 시작된 상황에서 이 메소드를 호출하면 예외 발생

출처 : 구글링 자료수집

ejb1.1_트랜잭션_관련사항_총정리강좌.doc

EJB3.0.pdf

FILE-20140206-000001_140206103400_1.pdf

JavaTransactionProgramming_02.doc

자바_트랜잭션_프로그래밍.pdf

https://technet.tmaxsoft.com/upload/download/online/jeus/pver-20150722-000001/server/chapter_tx_manager.html

이 글을 공유하기

댓글

Email by JB FACTORY