여니의 프로그래밍 study/Spring & Spring Boot

[Spring] DB 연동 - 2 (Chapter 8)

여니's 2023. 10. 8. 11:42

참고 자료 : 초보 개발자를 위한 스프링5 프로그래밍 입문


<Chapter8. DB 연동>

1. 트랜잭션 처리란?

: 두 개 이상의 쿼리를 한 작업으로 실행해야 할 때

사용하는 것이 바로 트랜잭션이다. 

 

트랜잭션은 여러 쿼리를 논리적으로 하나의 작업으로 묶는 작업이다.

한 트랜잭션으로 묶인 쿼리 중 하나라도 실패할 경우

전체 쿼리를 실패한 것으로 간주하고

DB 상태를 기존 상태로 되돌린다 (롤백)

 

트랜잭션으로 묶여있는 쿼리가 모두 성공할 경우

commint을 하여 반영한다. 

 

Connection conn=null;
try {
	conn= DriverManager.getConnection(jdbcUrl. user, pw);
    conn.setAutoCommit(false); // 트랜잭션 범위 시작
    --- 쿼리 실행
    conn.commit(); // 트랜잭션 범위 종료 : 커밋
} catch(SQLException ex) {	
	if (conn!=null)
    	// 트랜잭션 범위 종료 : 롤백
        try { conn.rollback();} catch (SQLException e) {}
 } finnaly {
 	if (conn!=null)
    	try { conn.close();} catch (SQLException e) {}
 }

 

2. @Transactional을 이용한 트랜잭션 처리

: 스프링에서 제공하는 어노테이션을 이용하면

트랜잭션 범위를 매우 쉽게 지정할 수 있다. 

트랜잭션 범위에서 실행하고 싶은 메서드에

해당 어노테이션을 붙이면 된다.

 

@Transactional
public void changePassword(String email, String oldPwd, String newPwd) {
	Member member = memberDao.selectByEmail(email);
    if (member == null)
    	throw new MemberNotFoundException();
    member.changePassword(oldPwd,newPwd);
    
    memberDao.update(member);
}

 

selectByEmail과 changePassword 메서드는

동일한 트랜잭션 범위에서 실행한다. 

즉, 한 트랜잭션에 묶인다. 

 

@Transactional이 동작하기 위해 스프링 설정에 추가해야한다

1) 플랫폼 트랜잭션 매니저 빈 설정

2) @Transactional 어노테이션 활성화 설정

 

@Bean
public Platform TransactionManager transactionManager() {
	DataSourceTransactionManager tm = new DataSourceTransactionManager();
    tm.setDataSource(dataSource());
    return tm;
}

 

PlatformTransactionManger는 스프링에서 제공하는

트랜잭션 매니저 인터페이스이다.

 

@EnableTransactionManagement 어노테이션은

@Transactional 어노테이션이 붙은 메서드를

트랜잭션 범위에서 실행하는 기능을 활성화한다.

 

 

트랜잭션이 시작되고 커밋되는 지 확인하려면

스프링이 출력하는 로그 메세지를 보면 된다. 

Logback을 사용하려면 

pom.xm 파일이나

build.gradle 파일에 해당 모듈을 추가하자

 

 

Logback은 로그 메세지 형식과 기록 위치를

설정 파일에서 읽어온다. 

 

 

3. @Transactional과 프록시

: 스프링은 해당 어노테이션으로 트랜잭션을 처리하기 위해서

내부적으로 AOP를 사용한다. 

AOP는 프록시를 통해 구현이 된다.

따라서 트랜잭션 처리도 프록시를 통해서 이루어진다. 

 

@EnableTransactionManagement 태그를 사용하면

스프링은 @Transactional 어노테이션이 적용된

빈 객체를 찾아서 알맞은 프록시 객체를 생성한다. 

 

스프링은 트랜잭션 기능을 적용하여 프록시 객체를 생성한다. 

MainForCPS 클래스에서 getBean 코드를 실행하면

ChangePasswordService 객체 대신에

트랜잭션 처리를 위해 생성한 프록시 객체를 리턴한다

 

@Transactional 어노테이션이 붙은 메서드를 호출하면

PlatformTransactionManager를 사용해서

트랜잭션을 시작하고

실체 객체의 메서드를 호출한 후 

성공적으로 실행되면 트랜잭션을 커밋한다.

 

 

4. @Transactional 적용 메서드의 롤백처리 과정

커밋 및 롤백을 처리하는 주체는 프록시 객체이다. 

원본 객체의 메서드를 실행하는 과정에서

RuntimeException이 발생하면

트랜잭션을 롤백한다.

 

 

별도 설정을 추가하지 않으면

발생한 익셉션이 RuntimeException일 때

트랜잭션을 롤백한다. 

 

SQLException은 RuntimeException을 상속하고 있지 않으므로

SQLException이 발생하면

트랜잭션을 롤백하지 않는다. 

만약 해당 익셉션이 발생할 때에도

롤백을 진행하고 싶다면

@Transactional의 rollbackFor 속성을 사용해야함

 

@Transactional(rollbackFor=SQLException.class)
public void someMethod() {
	...
}

 

4. @Transactional 의 주요 속성

속성 타입 설명
value String 트랜잭션을 관리할 때 사용할 PlatformTransactionManagement 빈의 이름을 지정함. 기본값은  " "이다
propagation Propagation 트랜잭션 전파 타입을 지정함
기본값은 Propagation.REQUIRED
> REQUIRED : 메서드 수행시 트랜잭션이 필요하다는 것을 의미함. 
isolation Isolation 트랜잭션 격리 레벨을 지정함
기본값은 isolation.DEFAULT
timeout int 트랜잭션 제한 시간을 지정함
기본값은 -1

 

 

5. @EnableTransactionManagement 어노테이션의 주요 속성

속성 설명
proxyTargetClass 클래스를 이용해서 프록시를 생성할지 여부를 지정함. 기본값은 false로서 인터페이스를 이용하여 프록시를 생성함
order AOP 적용 순서를 지정함. 기본값은 가장 낮은 우선순위에 해당하는 int 의 최댓값임

 

 

6. 트랜잭션 전파

: A 메서드에서 트랜잭션을 시작함

A 메서드에서 B 메서드를 호출하면

이미 A 메서드에 의해 시작된 트랜잭션이 존재하기에

B 메서드 호출시점에 트랜잭션을 새로 생성하지 않고

존재하는 트랜잭션을 그대로 사용한다.

따라서 A메서드와 B메서드를 한 트랜잭션으로

묶어서 실행하게 되는 것을 의미한다.