Transactions with Spring and JPA

강민욱·2023년 2월 22일
0

해당 게시물은 Baeldung 사이트를 기반으로 작성하였습니다.

1. 목표

JPA 트랜잭션에 대해서 알아보고 목적

2. 개요

올바른 Spring Transaction 설정과, @Transactional 사용법에 대해서 알아보자, 일반적으로 annotation, AOP를 사용하여 transaction을 설정한다.

3. Configure Transactions

@Configuration 클래스에 Spring 3.1에서 소개된 @EnableTransactionManagement 어노테이션을 사용하면 transactional 기능을 사용할 수 있다.
그러나 Springboot를 사용하고 있고 ‘spring-data-‘ 나 ‘spring-tx’ dependency를 사용하면 그냥 transaction관리를 할 수 있다.

4. The @Transactional Annotation

transaction이 구성돼있는 경우 메서드나 클래스에서 @Transactional을 사용할 수 있다.

@Service
@Transactional
public class FooService {
    //...
}

추가적인 기능도 지원하는데
(1) the Propagation Type of the transaction(transaction 전파형태)
(2) the Isolation Level of the transaction
(3) transaction이 명시된 동작의 timeout시간 설정
(4) readOnly flag : transaction이 읽기만할 persistence provider에 관한 힌트
(5) transaction rollback rule 설정
기본적으로 알아야 할 것은 rollback은 runtime시 unchecked exception에서만 발생한다. checked exception은 rollback의 트리거가 될 수 없다, 물론 rollbackFor, noRollbackFor annotation을 사용해서 동작을 컨트롤 할 수 있다.

5. Potential Pitfalls

(1) Transactions and Proxies

spring은 @Transactional이 선언된 모든 클래스에, 메소드 대해서 proxie를 만든다, proxy는 framework가 실행중인 method 전후에 transaction처리 로직을 주입할 수 있도록 한다, 주로 transaction을 시작하거나 commit에 관한 것이다.
주의해야 할 점은 transaction빈이 interface를 구현했다면 기본적으로 java dynamic proxy가 될 것이다. proxy를 통해 들어가는 외부호출만 인터셉트 된다. 어떤한 self-invocation 호출은 메소드가 @Transactional을 갖고 있더라도 어떠한 transaction도 시작할 수 없다.(내부 메소드 a에서 내부 메소드 b를 호출하는 경우 @Transactional 어노테이션에 의해 생성된 proxy 메소드를 호출할 수 없기 떄문에 transaction을 발생시킬 수 없다 정도로 이해)
다른 주의점은 public을 사용해야 한다. 다른 접근자들은 spring에 의해 proxy화 되지 않고 무시된다.

(2) Read-Only Transactions
readOnly flag는 보통 충돌을 발생시킨다, 특히 JPA로 작업할 때 더욱 그렇다,
javadoc를 보면

This just serves as a hint for the actual transaction subsystem; it will not necessarily cause failure of write access attempts. A transaction manager which cannot interpret the read-only hint will not throw an exception when asked for a read-only transaction.
이것을 실제 transaction subsystem을 위한 힌트에 불과하다, 반드시 쓰기동작이 실패하는 것도 아니다, transaction manager는 read-only를 해석할 수 없기 때문에 read only transaction을 요청할 때 exception을 발생시키지 않는다.

read-only 설정을 했을 때 insert, update가 발생하지 않는다고 확신할 수 없다, 이런한 동작은 vendor(database 업체?)에 따라 다르지만 JPA는 그렇지 않다.
read-only 옵션이 transaction 내부에서만 관련이 있다는 것은 중요하다. transaction영역 밖에서의 발생은 무시된다.

(3) Transaction Logging

transactional package에서 transaction관련 로그를 조정하는 것은 유용한 방법이다. 스프링에서 아래와 같은 방법으로 로깅레벨을 조정할 수 있다.

logging:
        level:
        org.springframework.transaction: DEBUG

(4) Transaction Rollback

transactional annotation은 메소드에 대한 transaction의 의미를 나타내는 metadata이다. rollback을 하는 두가지 방법은 선언적 방법과 프로그래밍방식 두가지가 있다.
선언적 방법에서 메소드에 @Transactional을 사용한다. 해당 annotation은 롤백을 하기 위한 rollbackFor or rollbackForClassName 두가지 속성이 있다. 반대로 롤백을 피하기 위한 noRollbackFor or noRollbackForClassName도 있다. 아래와 같이 list로 나열할 수도 있다

@Transactional(noRollbackFor = { ExceptionA.class, ExceptionB.class })
public void insertItem() {
        ...
}

선언적 방법에서 디폴트 롤백 동작은 runtime exceptions이나 errors 이다.
프로그램밍방식은 TransactionAspectSupport을 사용하는것이다.

public void createCourseDefaultRatingProgramatic(Course course) {
    try {
        courseDao.create(course);
    } catch (Exception e) {
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }
}

위와 같이 catch문에 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 해당 명령어를 사용하여 rollback을 강제할 수 있다.

profile
백엔드 개발자

0개의 댓글