3-20 서비스 계층의 분리와 @Transaction(2)

서현우·2022년 5월 19일
0

스프링의정석

목록 보기
47/85

1. 서비스 계층(Layer)의 분리 - 비지니스 로직의 분리

2. TransactionManager란?

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);

3. TransactionManager로 Transaction 적용하기

//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 사용가능

4. @Transactional로 Transaction 적용하기

AOP를 이용한 핵심 기능과 부가 기능의 분리

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);
} //핵심 로직만 집중 가능

@Transactional은 클래스나 인터페이스에도 붙일 수 있음.

  • 클래에 붙이면 클래스 내의 모든 메서등 ㅔ적용.
  • 인터페이스에 붙이면, 인터페이스를 구현하는 클래스의 모든 메서드에 적용.

@Transactional의 속성

progagation : Tx의 경계(boundary)를 설정하는 방법을 지정.
isolation : Tx의 isolation level을 지정.
readOnly : Tx이 데이터를 읽기만 하는 경우, true로 지정하면 성능 향상.
rollbackFor : RuntimeException, Error는 자동 rollback.
noRollbackFor : Tx을 rollback하지 않음.
timeout : 지정된 시간(초) 내에 Tx이 종료되지 않으면, Tx를 강제 종료.

propagation속성의 값

REQUIRED : Tx이 진행중이면 참여, 없으면 새로운 Tx 시작(디폴트)
REQUIRES_NEW : Tx이 진행 중이건 아니건, 새로 Tx 시작(Tx 안에 다른 Tx)
NESTED : Tx이 진행 중이면, Tx의 내부 Tx로 실행(Tx안에 subTx)(같은 Tx)
MANDATORY
SUPPORTS
NOT_SUPPORTED
NEVER

REQUIRED와 REQUIREDS_NEW (1) - REQUIRED

//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와 REQUIRES_NEW(2) - REQUIRES_NEW

//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
profile
안녕하세요!!

0개의 댓글