3-19 ~ 3-21 @Transaction

서현우·2022년 5월 31일
0

복습

목록 보기
29/34

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

2개의 계층

컨트롤러의 역할에 비지니스로직은 포함X => 3개의 계층으로 분리 해야 함.

//2개의 계층일 때(Controller, DAO)
RegisterController
주입
- userDao: UserDao
- userHistoryDao: UserHistoryDao
메서드
+ toDate(WebDataBinder): void
+ add(): String
+ save(User, BindingResult): String
- loginCheck(String, String): boolean

UserDao
주입
- ds: DataSource
메서드
+ selectUser(String): User
+ insertUser(User): int
+ deleteUser(String): int
+ updateUser(User): int
+ deleteAll(): int
+ selectAll(): List

UserHistoryDao
주입
- ds: DataSource
메서드
+ selectUserHistory(String): List
+ insertUserHistory(History): int
+ deleteUserHistory(String): int
+ updateUserHistory(History): int
+ deleteAll(): int
+ selectAll(): List
//3개의 계층일 때(Controller, Service, DAO)
//1. Presentation Layer
//@Controller
RegisterController
주입
- userService: UserService
메서드
+ toDate(WebDataBinder): void
+ add(): String
+ save(User, BindingResult): String
- loginCheck(String, String): boolean

//2. Service Layer(비지니스 로직)
//Tx적용에 유리
//@Service
UserService
주입
- userDao: UserDao
- userHistoryDao: UserHistoryDao
메서드
+ registerUser(User): int
+ getUserHistory(User): int
+ addHistory(History): int
+ changeStatus(User): int

//DB는 영속계층
//3. Persistence Layer(영속계층)
//@Repository
UserDao
주입
- ds: DataSource
메서드
+ selectUser(String): User
+ insertUser(User): int
+ deleteUser(String): int
+ updateUser(User): int
+ deleteAll(): int
+ selectAll(): List

UserHistoryDao
주입
- ds: DataSource
메서드
+ selectUserHistory(String): List
+ insertUserHistory(History): int
+ deleteUserHistory(String): int
+ updateUserHistory(History): int
+ deleteAll(): int
+ selectAll(): List

DB

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

But Tx는 1개의 Connection에서 처리돼야함.
==> TransactionManager가 필요(같은 Tx면 같은 Connection이 사용되도록)
DAO에서 Connection을 얻거나 반환할 때 DataSourceUtils를 사용해야 함.

//이전 방법
conn = ds.getConnection();
try { if(conn!=null) conn.close(); }
catch(SQLException e) {e.printStackTrace();}

//DataSourceUtils 사용
conn = DataSourceUtils.getConnection(ds);
DataSourceUtils.releaseConnection(conn, ds);

3. TransactionManager로 Transaction 적용하기

//Tx매니저 직접 생성 방법
public void insertWithTx() throws Exception {
	//Tx매니저 생성
	PlatformTransactionManager tm = new DataSourceTransactionManager(ds);
	//Tx의 속성을 정의
	TransactionStatus status = tm.getTransaction(new DefaultTransactionDefinition());
	//Tx 시작
	try {
		a1Dao.insert(1,100);
		a1Dao.insert(1,200);
		tm.commit(status); //Tx끝 - 성공
	} catch(Exception ex) {
		tm.rollback(status); //Tx끝 - 실패
	}
}
//Tx매니저를 빈으로 등록 방법
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource"/>
</bean>
<!-- @Transactional 사용 가능 -->
<tx:annotataion-driven/>

4. @Transactional로 Transaction적용하기

AOP를 이용한 핵심 기능과 부가 기능의 분리
@Transactional은 클래스나 인터페이스에도 붙일 수 있음
(클래스, 인터페이스에 붙이면 클래스, 인터페이스 내의 모든 메서드에 적용)

//AOP로 위의 코드의 핵심기능만 분리
@Transactional
public void insertWithTx() throws Exception {
	a1Dao.insert(1,100);
	a1Dao.insert(1,200);
}

5. @Transactional의 속성

isolation : Tx의 isolation level을 지정.
readOnly : 읽기전용. 성능향상.
rollbackFor : Exception.class일 때
noRollbackFor : 반대
timeout : 시간제한 --> 강제종료
propagation : Tx의 경계를 설정하는 방법을 지정.

6. propagation속성의 값

REQUIRED : Tx이 진행중이면 참여하고, 없으면 새로운 Tx 시작(디폴트)
REQUIRES_NEW : Tx이 진행 중이건 아니건, 새로 Tx 시작(Tx안에 다른 TX)
NESTED : Tx이 진행 중이면, Tx의 내부 Tx로 실행(Tx안에 subTx)(savePoint)

7. REQUIRED와 REQUIRES_NEW

(1)REQUIRED

//두 Tx가 같은 Tx처럼 돌아감.
//예외 발생 시 처음으로 rollback
//REQUIRED는 기본값이라 생략해도 됨.
@Transactional(propagation = Propagation.REQUIRED)
public void insertA1WithTx() throws Exception {
	a1Dao.insert(1, 100);
	insertB1WithTx();
	a1Dao.insert(1, 200);
}
@Transactional(propagation = Propagation.REQUIRED) {
	b1Dao.insert(1, 100);
	b1Dao.insert(1, 200);
}

(2)REQUIRES_NEW

//@Transactional(propagation = Propagation.REQUIRED)
@Transactional
public void insertA1WithTx() throws Exception {
	a1Dao.insert(1, 100);
	insertB1WithTx();
	a1Dao.insert(1, 200);
}
//새로운 별도의 Tx생성
@Transactional(propagation = Propagation.REQUIRES_NEW) 
public void insertB1WithTx() throws Exception {
	b1Dao.insert(1, 100);
	b1Dao.insert(1, 200);
}
profile
안녕하세요!!

0개의 댓글