[Spring] @Transactional이 뭐길래

eunniverse·2024년 5월 17일
0

글 쓰게된 계기

'eunniverse씨, 이것 좀 대응해줘!', 팀장님의 다급한 호출!
하던 일을 멈추고 후다닥 보는데, API를 호출할 때 파라미터가 넘어가지 않았다.
분명 DB에 데이터를 INSERT 하고, API를 호출했는데.. 왜!!!! 안넘어갈까?
고민하던 와중 눈에 보였던 @Transactional 어노테이션!!!!

그렇다.. 결론은 @Transactional 설정 문제 였다.
분명 알고 있는 개념임에도 막상 찾으려니까 헤매였던 경험을 토대로 글을 써야지 싶어서 적는 글 -_-!


그래서 정확한 문제는?

// 데이터 추가
@Transactional(rollbackFor = Exception.class)
public void insertObject(Data data) {
    try {
         dao.insertObject(data);
         ....
         this.updateObject(data);
         callAPI();
        
    } catch(Exception e) {
         ....
    }
}
// 데이터 업데이트
@Transactional(rollbackFor = Exception.class)
public void updateObject(Data data) {
    try {
    	....
    } catch(Exception e) {
        ....
    }
}
// API 호출 메서드
public void callAPI() {
    try {
    	ResponseObject res = this.httpPost();
    } catch(Exception e) {
    	log.error(e.getMessage());
    }
}

@transactional이 걸려있기 때문에 데이터가 업데이트되지 않은 채로 api를 호출해서 오류가 발생한 것이었다.


그래서 어떻게 해결했나?

@transactional 에 있는 propagation 속성의 REQUIRED_NEW 를 사용했다.

transactional propagation 즉, 트랜잭션 전파 는 무엇인가??

트랜잭션 전파 의미

트랜잭션을 시작하거나, 기존 트랜잭션에 참여하는 방법을 결정하는 속성이다. 트랜잭션 경계의 시작 지점에서 트랜잭션 전파 속성을 참조해서 해당 범위의 트랜잭션을 어떤 식으로 진행시킬지 결정할 수 있다.

트랜잭션 전파 속성

1. REQUIRED
Defualt 속성이며, 모든 트랜잭션 매니저가 지원한다. 보통 이 속성으로 많이 사용한다. 미리 시작된 트랜잭션이 있으면 참여하고, 없으면 트랜잭션을 생성한다. 간단한 트랜잭션 전파 방식이지만 사용해보면 매우 강력하고 유용한 속성이라는 사실을 알 수 있다.

2. SUPPORTS
이미 시작된 트랜잭션이 있으면 참여하고 없으면 트랜잭션 없이 진행한다. 트랜잭션이 없긴 하지만 해당 경계 안에서 Connection이나 Hibernate Session 등을 공유할 수 있다.

3. MANDATORY
REQUIRED와 비슷하며, 이미 시작된 트랜잭션이 있으면 참여한다. 하지만 트랜잭션이 없다면 생성하는 것이 아니라 예외를 발생시킨다. 혼자서 독립적으로 트랜잭션을 실행하면 안되는 경우에 사용한다.

4. NOT_SUPPORTED
트랜잭션을 사용하지 않게 한다. 이미 진행 중인 트랜잭션이 있으면 보류시킨다.

5. REQUIRES_NEW
항상 새로운 트랜잭션을 시작한다. 이미 진행 중인 트랜잭션이 있다면, 트랜잭션을 보류시킨다.

6. NEVER
트랜잭션을 사용하지 않도록 강제한다. 이미 진행 중인 트랜잭션도 존재하면 안되며, 트랜잭션이 있다면 예외를 발생시킨다.

데이터 추가 -> 업데이트된 상태에서 API 호출이 되어야했기 때문에 transaction 순서 변경이 필요했다. 그래서 'REQUIRES_NEW' 를 지정해주어 매번 새로운 트랜잭션이 시작되게끔 처리했고, 의도한 순서대로 처리가 되었다!


(부록) @Transactional이 뭐길래?

의미

spring 에서는 어노테이션 방식으로 transaction을 지원한다.

클래스 또는 메서드 위에 @Transactional을 붙이면, 트랜잭션 기능이 적용된 프록시 객체가 생성되며, 트랜잭션 성공 여부에 따라 Commit 또는 Rollback 작업이 이루어진다.

동작원리

import org.springframework.transaction.annotation.Transactional;

import 문을 보면 알 수 있듯이 트랜잭션은 어노테이션 기반 AOP를 통해 구현되어있다.

따라서, 가지게 되는 특징은 다음과 같다.

1. 클래스, 메소드에 @Transactional이 선언되면 트랜잭션이 적용된 프록시 객체 생성
2. 프록시 객체는 @Transactional이 포함된 메서드가 호출될 경우, 트랜잭션 시작
3. 예외가 없을 때는 Commit 예외가 발생하면 Rollback 진행
profile
능력이 없는 것을 두려워 말고, 끈기 없는 것을 두려워하라

0개의 댓글