하이버네이트 애플리케이션의 트랜잭션
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들이 분류되어 있다.
- HibernateExcepion은 getCause()를 사용해서 좀 더 구체적인 정보를 확인해봐야 한다.
- JDBCException은 SQL 문에서 발생한 에러이다. getSQL()을 호출하여 SQL을 확인해볼 수 있다. DB 벤더 에러 코드를 보려면 getErrorCode()를 호출하면 된다.
JTA를 사용하여 코드에서 트랜잭션 처리하기
- JTA의 javax.transaction.UserTransaction 인터페이스를 사용하여 리소스를 관리한다.
- 꼭 Application Seerver가 있어야만 JTA를 사용할 수 있는 건 아니다. JBoss
Transactions는 오픈소스 독립적인 JTA 프로바이더를 제공한다. 이것을 Tomcat에서 돌리고 있는 하이버네이트
애플레키에션에 설치할 수 있다.
- JTA로 관리되는 리소스를 사용하는 장점
- 트랜잭션 관리 서비스는 모든 리소스를 통합하고 트랜잭션 제어를 단일 표준 API로 관리할 수 있도록 해준다.
- JEE 트랜잭션 관리자는 여러개의 리소스를 하나의 트랜잭션으로 묶어서 관리할 수 있다.
- JTA 구현체의 품질이 간단한 JDBC 커넥션 풀 보다 좋다.
- JTA 프로바이더는 런타인시에 불필요한 오버헤드를 발생시키지 않는다.
- 하이버에서 JTA 트랜잭션 사용하기
- 애플리케이션 코드는 수정할 필요 없이 그냥 하이번네이트의 Transaction API를 사용한다.
- 설정파일에서 hibernate.transaction.factory_class 속성의 값을 org.hibernate.transaction.JTATransactionFactory로 설정한다.
- hibernate.transaction.manager_lookup_class
속성의 값에 JTA 구현체의 Lookup 클래스를 설정해준다.(ex.
org.hibernate.transaction.JBossTransaction-ManagerLookup) - 하이버는 더이상 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 클래스로 설정.