DAO의 각 메서드는 개별 Connection을 사용.
@Repository
public class UserDaoImpl implements UserDao {
@Autowired DataSource ds;
public int deleteUser(String id) {
Connection conn = null;
PreparedStatement pstmt = null;
String sql = "delete from user_info where id= ? ";
try{
conn = ds.getConnection();
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, id);
return pstmt.executeUpdate();
...
같은 Tx내에서 같은 Connection을 사용할 수 있게 관리.
DAO에서 Connection을 얻거나 반환할 때 DataSourceUtils를 사용해야
conn = ds.getConnection();
//...
try{ if(conn!=null) conn.close(); }
catch(SQLException e) { e.printStackTrace(); }
//아래처럼 변환 시켜야 함.
conn = DataSourceUtils.getConnection(ds);
//...
DataSourceUtils.releaseConnection(conn, ds);
//DataSourceTransactionManager(ds) //TxManager 생성
public void inserWithTx() throws Exception {
PlatformTransactionManager tm = new DataSourceTransactionMangager(ds);
//DefaultTransactionDefinition //Tx의 속성을 정의
TransactionStatus status = tm.getTransaction(new DefaultTransactionDefinition());
//Tx 시작
try {
a1Dao.insert(1,100);
a1Dao.insert(1,200);
t.commit(status); //Tx 끝 - 성공(커밋)
} catch(Exception ex) {
tm.rollback(status); //Tx 끝 - 실패(롤백)
}
}
빈으로 등록하는 방법
<bean id="transactionManager" class="org.springframework.jdbc.datesource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven/> //@Transactional 사용가능
public void insertWithTx() throws Exception {
PlatformTransactionManager tm = new DataSourceTransactionManager(ds);
TransactionStatus status = tm.getTransaction(new DefaultTransactionDefinition());
try {
a1Dao.insert(1,100);
a1Dao.insert(1,200);
tm.commit(status);
} catch(Exception ex) {
tm.rollback(status);
}
}
==> 핵심 기능 분리
@Transactional
public void insertWithTx() throws Exception {
a1Dao.insert(1,100);
a1Dao.insert(1,200);
} //핵심 로직만 집중 가능
progagation : Tx의 경계(boundary)를 설정하는 방법을 지정.
isolation : Tx의 isolation level을 지정.
readOnly : Tx이 데이터를 읽기만 하는 경우, true로 지정하면 성능 향상.
rollbackFor : RuntimeException, Error는 자동 rollback.
noRollbackFor : Tx을 rollback하지 않음.
timeout : 지정된 시간(초) 내에 Tx이 종료되지 않으면, Tx를 강제 종료.
REQUIRED : Tx이 진행중이면 참여, 없으면 새로운 Tx 시작(디폴트)
REQUIRES_NEW : Tx이 진행 중이건 아니건, 새로 Tx 시작(Tx 안에 다른 Tx)
NESTED : Tx이 진행 중이면, Tx의 내부 Tx로 실행(Tx안에 subTx)(같은 Tx)
MANDATORY
SUPPORTS
NOT_SUPPORTED
NEVER
//REQUIRED : Tx가 기존에 있으면 새로 Tx 안만듬
@Transactional(propagation = Propagation.REQUIRED)
public void insertA1WithTx() throws Exception {
a1Dao.insert(1, 100);
insertB1WithTx();
a1Dao.insert(1, 200);
}
@Transactional(propagation = Propagation.REQUIRED)
public void insertB1WithTx() throws Exception {
b1Dao.insert(1, 100);
b1Dao.insert(1, 200);
}
//결과 1개의 Tx.
//REQUIRED가 기본값이라 @Transactional로 써도 됨.
@Transactional(propagation = Propagation.REQUIRED)
public void insertA1WithTx() throw Exception {
a1Dao.insert(1, 100);
insertB1WithTx();
a1Dao.insert(1, 200);
}
//REQUIRES_NEW : 새로운 Tx가 필요.
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void insertB1WithTx() throws Exception {
b1Dao.insert(1, 100);
b1Dao.insert(1, 200);
}
//결과 2개의 Tx