[출처]: 스프링의 정석
Controller는 단순호출만 하고 UserService(비지니스 로직)에서 여러 정책들을 관리한다. (회원 포인트,회원정보 등등)
UserDao의 각 메서드들은 각각의 connection을 갖는다. 그 의미는 메서드를 호출하고 나면 commit이 되어버린다는 것이다. commit이 되면 rollback을 할 수가 없다.
때문에 하나의 transaction으로 이어져야 하는 것들을 모아서 한번의 관리해주는 것을 TransactionManager라고 한다.
이렇게 하기 위해서는 기존에
conn = ds.getConnection();
//...
try{if(conn)!=null} conn.close();} //반환
catch(SQLException e){e.printStackTrace();}
이렇게 사용하던것을 아래처럼 바꿔줘야 한다.
conn = DataSourceUtils.getConnection(ds);
//...
DataSourceUtils.releaseConnection(conn,ds);
좀더 자세하게 들어가면
public void insertWithTx() throws Exception{
PlatformTransactionManager tm = new DataSourceTransactionManager(ds);
TransactionStatus status = tm.getTransaction(new DefaultTransactionDefinition()); // DefaultTransactionDefinition은 Tx의 속성을 정의한다. 일단은 Default값으로
try{
a1Dao.insert(1,100);
a1Dao.insert(1,200);
tm.commit(status); //Tx끝 -성공(커밋)
}catch(Exception ex){
tm.rollback(status); // Tx끝 - 실패(롤백)
}
}
TransactionManager가 같은 connection을 사용하게 해준다.
위처럼 직접 등록하지 않고 bean으로 등록하는 방법도 있다.
<bean id ="transactionManger" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven/> // 이게 있어야 @Transactional 사용 가능
위의 코드를 AOP로 바꿔주면 다음과 같다.
@Transactional
public void insertWithTx() throws Exception{
a1Dao.insert(1,100);
a1Dao.insert(1,200);
}
@Transactional을 붙여줌으로써 해당 메서드를 실행할때 앞뒤 코드가 같이 실행된다.
만약 @Transactional을 class에 붙인다면, 해당 class안에 있는 모든 메서드에서 실행된다. interface도 마찬가지다.
REQUIRED_NEW와 NESTED를 많이 헷갈리는데, 전자는 서로 아예 다른 Tx이고 후자는 같은 Tx의 sub느낌이다.