1. 트랜잭션 경계설정
JDBC의 트랜잭션
- 하나의 커넥션을 가져와 사용하다가 닫는 사이에 이루어진다.
- 따라서 트랜잭션은 커넥션과 주기를 같이한다.
Connection c = dataSource.getConnection();
c.setAutoCommit(false); // 트랜잭션 시작
try {
PreparedStatement ps = c.prepareStatement("update user...");
c.commit(); // 트랜잭션 커밋
catch (Exception e) {
c.rollback(); // 트랜잭션 롤백
}
}
2. 트랜잭션 동기화
트랜잭션 동기화란?
- Connection 오브젝트를 특별한 저장소에 보관해 둔 뒤, 가져다 쓰는 방식이다.
트랜잭션 동기화 적용
- TransactionSynchronizationManager.initSynchronization() -> 트랜잭션 동기화 작업을 초기화
- TransactionSynchronizationmanager.unbindResource(dataSource); / TransactionSynchronizationManager.clearSynchronization() -> 트랜잭션 동기화 작업 종료 및 정리
public void upgradeLevels() throws Exception {
TransactionSynchronizationManager.initSynchronization();
Connection c = DataSourceUtils.getConnection(dataSource);
c.setAutoCommit(false);
try {
List<User> users = userDao.getAll();
for (User user : users) {
if(canUpgradeLevel(user)) {
upgradeLevel(user);
}
}
c.commit();
} catch (Exception e) {
c.rollback();
throw e;
} finally {
DataSourceUtils.releaseConnection(c, dataSource);
TransactionSynchronizationManager.unbindResource(this.dataSource);
TransactionSynchronizationManager.clearSynchronization();
}
}
문제점
- 하이버네이트는 Connection 이 아닌 Session 을 사용 -> 변경에 불리.
- 이를 위해서 스프링이 제공하는 트랜잭션 서비스 추상화를 사용해서 Connection을 감추도록 해보자
3. 스프링의 트랜잭션 서비스 추상화
스프링은 PlatformTransactionManager 인터페이스 를 통해 트랜잭션 경계설정을 위한 서비스 추상화를 제공한다.
- 토비의 스프링 책에서는 Jdbc 를 사용하므로 PlatformTransactionManager 를 구현한 DataSourceTransactionManager 를 사용한다.
위의 코드를 스프링이 제공하는 추상화 인터페이스를 통해서 변경해보자
- PlatformTransactionManager transactionManger = new DataSourceTransactionManager(dataSource); -> 트랜잭션 추상화 객체 생성
- TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition()) -> 트랜잭션 시작
public void upgradeLevels() {
PlatformTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);
TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
try {
List<User> users = userDao.getAll();
for (User user : users) {
if(canUpgradeLevel(user)) {
upgradeLevel(user);
}
}
transactionManager.commit(status);
} catch (RuntimeException e) {
transactionManager.rollback(status);
throw e;
}
}