Java SE에서의 코딩을 통한 트랜잭션

  • hibernate.transaction.factory_class 설정 기본 값이 org.hibernate.transaction.JDBCTransactionFactory로 되어 있기 때문에 별도의 설정이 필요없다.
  • TransactionFactory 구현체를 만들어서 Transaction 인터페이스를 확장하거나 커스터마이징 할 수 있다.
Session session = null;
Transaction tx = null;
try {
session = sessionFactory.openSession();
tx = session.beginTransaction();
concludeAuction(session);
tx.commit();
} catch (RuntimeException ex) {
tx.rollback();
} finally {
session.close();
}
  • JDBC Connection은 트랜잭션이 시작할 때 얻어온다.
  • beginTransaction()은 setAutoCommit(false)를 설정하게 된다.
  • 이렇게 하면 Session이 db 커넥션과 묶이게 된다.
  • 트랜잭션을 commit() 하면 db 커넥션은 반환되고, Session을 풀리게 된다. 또 다른 트랜잭션을 해당 Session에서 시작하면, 새로운 커넥션을 얻어온다.

예외 처리하기

  • 3쩜대 버전 부터는 하이버네이트의 모든 메소드가 RuntimeException을 던지게 되어 있다.
  • tx.rollback() 마져도 RuntimeException을 던지기 때문에, 로깅을 남길 때, Exception객체를 인자로 넘겨주는 것을 잊지 않도록 한다.
  • tx.setTimeout(int second)를 사용하여 일정 시간 이내에 처리되지 않으면 예외를 던지도록 설정할 수 있다.
  • Exception들이 분류되어 있다.
  1. HibernateExcepion은 getCause()를 사용해서 좀 더 구체적인 정보를 확인해봐야 한다.
  2. JDBCException은 SQL 문에서 발생한 에러이다. getSQL()을 호출하여 SQL을 확인해볼 수 있다. DB 벤더 에러 코드를 보려면 getErrorCode()를 호출하면 된다.

JTA를 사용하여 코드에서 트랜잭션 처리하기

  • JTA의 javax.transaction.UserTransaction 인터페이스를 사용하여 리소스를 관리한다.
  • 꼭 Application Seerver가 있어야만 JTA를 사용할 수 있는 건 아니다. JBoss
    Transactions는 오픈소스 독립적인 JTA 프로바이더를 제공한다. 이것을 Tomcat에서 돌리고 있는 하이버네이트
    애플레키에션에 설치할 수 있다.
  • JTA로 관리되는 리소스를 사용하는 장점
  1. 트랜잭션 관리 서비스는 모든 리소스를 통합하고 트랜잭션 제어를 단일 표준 API로 관리할 수 있도록 해준다.
  2. JEE 트랜잭션 관리자는 여러개의 리소스를 하나의 트랜잭션으로 묶어서 관리할 수 있다.
  3. JTA 구현체의 품질이 간단한 JDBC 커넥션 풀 보다 좋다.
  4. JTA 프로바이더는 런타인시에 불필요한 오버헤드를 발생시키지 않는다.
  • 하이버에서 JTA 트랜잭션 사용하기
  1. 애플리케이션 코드는 수정할 필요 없이 그냥 하이번네이트의 Transaction API를 사용한다.
  2. 설정파일에서 hibernate.transaction.factory_class 속성의 값을 org.hibernate.transaction.JTATransactionFactory로 설정한다.
  3. hibernate.transaction.manager_lookup_class
    속성의 값에 JTA 구현체의 Lookup 클래스를 설정해준다.(ex.
    org.hibernate.transaction.JBossTransaction-ManagerLookup)
  4. 하이버는 더이상 JDBC 커넥션 풀을 관리하지 않는다. 커넥션들을 JNDI를 통해서 JTA 프로바이더로부터 받아온다.
  • JTA를 사용할때와 그렇지 않을 때의 차이

    • JTA를 사용할 때: DB 커넥션을 Session을 사용하려고 할 때 가져온다.(more aggressive), 같은 트랜잭션 내에서는 항상 같은 커넥션을 가져오도록 Application Server가 보장해준다.
    • JTA를 사용하지 않을 때: DB 커넥션을 트랜잭션 시작할 때 가져와서 끝날 때 반환한다.
  • JTA 시스템은 전역적인 트랜잭션 타임아웃을 지원한다.
UserTransaction utx = (UserTransaction) new InitialContext()
.lookup("java:comp/UserTransaction");
Session session1 = null;
Session session2 = null;
try {
utx.begin();
session1 = auctionDatabase.openSession();
session2 = billingDatabase.openSession();
concludeAuction(session1);
billAuction(session2);
session1.flush();
session2.flush();
utx.commit();
} catch (RuntimeException ex) {
try {
utx.rollback();
} catch (RuntimeException rbEx) {
log.error("Couldn't roll back transaction", rbEx);
}
throw ex;
} finally {
session1.close();
session2.close();
}
  • JTA 인터페이스를 사용하여 구현할 때에 기본 설정은 명시적으로 flush()를 해야하며, session도 명시적으로 닫아줘야 한다.
  • hibernate.trans-action.flush_before_completion 속성과 hibernate.transaction.auto_close_session 속성을 설정하면 코드를 줄일 수 있다.
UserTransaction utx = (UserTransaction) new InitialContext()
.lookup("java:comp/UserTransaction");
Session session1 = null;
Session session2 = null;
try {
utx.begin();
session1 = auctionDatabase.openSession();
session2 = billingDatabase.openSession();
concludeAuction(session1);
billAuction(session2);
utx.commit();
} catch (RuntimeException ex) {
try {
utx.rollback();
} catch (RuntimeException rbEx) {
log.error("Couldn't roll back transaction", rbEx);
}
throw ex;
}
  • 가능하면 JTA를 직접 사용하기를 권하고 있다. 이식성을 애플리케이션 밖으로 끌어내기 위해서..

컨테이너가 관리하는 트랜잭션

  • 선언적인 트랜잭션 경제는 컨테이너에게 트랜잭션 관리의 책임을 넘기는 것이다.(스프링은 IoC 컨테이너에게 넘긴다. 여기서는 WAS를 얘기하고 있음.)
  • CMT는 독입적인 JTA 구현체에서는 제공하지 않는다.
@Stateless
public class ManageAuctionBean implements ManageAuction {
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void endAuction(Item item) {
Session session1 = auctionDatabase.openSession();
Session session2 = billingDatabase.openSession();
concludeAuction(session1, item);
billAuction(session2, item);
}
...
}
  • 컨테이너가 TransactionAttribute를 읽은 뒤, 그에따라 트랜잭션을 적용한다.
  • 위에서는 REQUIRED기 때문에 현재 트랜잭션이 있으면 그걸 사용하고 없으면 새로 만들어서 사용한다.
  • 필요한 설정

    • hibernate.transaction.factory_class 속성을 org.hibernate.transaction.CMTTransactionFactory 로 설정.
    • hibernate.transaction.manager_lookup_class 속성을 사용하는 application server의 lockup 클래스로 설정.