«   2022/01   »
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          
Archives
Today
62
Total
864,818
관리 메뉴

래빗 크리스

트랜잭션은 동일한 Connection 안에서만 먹습니다. 본문

2. 컴퓨터 이야기/프로그래밍

트랜잭션은 동일한 Connection 안에서만 먹습니다.

래빗 크리스 2009. 4. 2. 13:36

당연한 이야기인가요..?

그런데, 손에 익지 않은 프레임웍을 사용한다면, 트랜잭션이 작동하지 않아서 DB 에 Commit 이 먹지 않을 수도 있습니다.
다른 프레임웍의 패키지를 끌어다 사용할때 트랜잭션이나 Commit 이 어떻게 동작하는지 충분히 확인해 보아야 합니다.
특히나, 프로그램에서 호출하는 프로시저에서 별도의 Commit 로직이 있다면 전체 트랜잭션과 따로 놀겠죠..
상기와 같은 이유 말고도 여러가지 이유들이 있겠습니다.. 크윽.

하나의 트랜잭션으로 묶었으면 그 안에서 동일하게 돌아가야 하는데, 꼭 한두 개는 따로 노는 넘(?)들이 있더군요.
아무튼, 트랜잭션을 설정할 때, 이 부분을 잘 살펴 보아야 합니다.

서버 단에서의 조치라면.. 다음과 같은 것이 가능하겠습니다.
이기종 DB나 다른 DB 를 끌어다 사용한다면 DB Link (오라클 외에서는 어떤 명칭으로 부르나요..?) 로 묶어 사용하거나,
요즘에 나오는 Application Server 는 이기종 DB 에서도 하나의 트랜잭션으로 묶을 수 있더군요.
아, 이것도 벌써 오래 전에 구현이 되었군요.
그렇다면 역시, 애플리케이션(Java 등등) 단에서의 조치가 필요하다는 결론이군요.

만약 A 패키지 안의 클래스 메소드(Aa)에서 B 패키지의 메소드(Bb)를 끌어다 사용해야 한다면,
다시 말해서 Aa 메소드 중 트랜잭션으로 묶이는 부분에 Bb 메소드가 사용될때..
Bb 안에서도 트랜잭션이 있다면 Bb 를 사용하면 안 되고,
Bb 와 기능은 동일하지만 트랜잭션이 걸려있지 않은 새로운 메소드를 구현하여 사용해야 합니다.
이 글을 쓰게된 이유가 바로 여기에 있네요. 설명이 장황했습니다만..

문제의 Bb 소스의 대략적인 구조가 아래와 같습니다. 트랜잭션 처리가 되어 있습니다.
public boolean addArticleInfo(ArticleInfo info) throws Exception{ 

  Transaction  tx     = null; 
  ArticleDao  dao     = null; 
  boolean    result    = false;

  try{

    tx           = TransactionFactory.getInstance();
    tx.begin();
    dao           = new ArticleDao();
    ...

  }catch(Exception e){
    tx.rollback();
    throw e;
  }finally{
    tx.commit();
  }

  return result;
 }


문제의 Aa 메소드 입니다. 여기에서도 트랜잭션이 설정되어 있습니다.
Aa 메소드 만 놓고 보면 트랜잭션이 잘 먹혀들어갈 것같지만..
Bb 안에서 트랜잭션을 별도로 운영하기 때문에 결과적으로는 다른 트랜잭션으로 움직이고, DB 에는 반영되지 않겠죠.
따라서 Ba 에서 트랜잭션을 뺀 내용으로 별도의 메소드를 만들고, Aa 에서 이를 가져다 사용해야 합니다.

public boolean addEmailInfo(EventEmailInfo info) throws Exception{ 

  Transaction   tx     = null; 
  boolean     result    = false;

  try{

    tx            = TransactionFactory.getInstance();
    tx.begin();

    String    c1     = info.getContent1()==null ? "" : info.getContent1();
    String    c2     = info.getContent2()==null ? "" : info.getContent2();

    ArticleMng  articleMng = new ArticleMng();
    ArticleDao  dao     = new ArticleDao();
    ArticleInfo  info2    = new ArticleInfo();
    info2.setSeqCategory(info.getSeqCategory());
    info2.setIsrtId(info.getIsrtId());
    info2.setOpenYn("Y");
   
    info2.setOrderIsrtId(1);
    info2.setTitle("제1문항");
    info2.setContent(c1);
    result          = articleMng.addArticleInfo(info2, dao);
    if(!result){ tx.rollback(); return false; }
   
    info2.setOrderIsrtId(2);
    info2.setTitle("제2문항");
    info2.setContent(c2);
    result          = articleMng.addArticleInfo(info2, dao);
    if(!result){ tx.rollback(); return false; }

  }catch(Exception e){
    tx.rollback();
    throw e;
  }finally{
    tx.commit();
  }
  
   return result;
 }


2 Comments
  • 프로필사진 Favicon of https://rabbitchris.tistory.com BlogIcon 래빗 크리스 2009.04.02 22:29 신고 물론, 본문에서 이야기 하는 프로시저는 DB 의 Stored Procedure 입니다.
  • 프로필사진 Favicon of https://rabbitchris.tistory.com BlogIcon 래빗 크리스 2013.06.04 10:43 신고 Context 와 DataSource 를 통하여 Connection 을 사용하는 경우에는..

    try{

    ctx = new InitialContext();
    source = (DataSource)ctx.lookup("...");
    con = source.getConnection();
    con.setAutoCommit(false); // 트랜잭션 시작
    ...
    con.commit(); // 정상 작동인 경우 커밋. try 문의 맨 마지막에 위치

    }catch(Exception e){
    con.rollback(); // 오동작인 경우 롤백. DB를 먼저 풀어주려고 catch 맨 처음에 위치.
    ...
    }catch(SQLException e){
    con.rollback(); // 오동작인 경우 롤백. DB를 먼저 풀어주려고 catch 맨 처음에 위치.
    ...
    }finally{
    con.setAutoCommit(true); // 트랜잭션 마무리, finally 문에 설치
    if(rs!=null){ rs.close(); rs=null; }
    if(pstmt!=null){ pstmt.close(); pstmt=null; }
    if(con!=null){ con.close(); con=null; }
    }
댓글쓰기 폼