Spring

@Transactional 에 대한 고찰

wangkisa 2023. 3. 26. 21:43

 스프링에서 트랜잭션 처리를 지원하는데 어노테이션 방식으로 @Transactional 을 선언하여 사용하는데,

여기서 얘기하는 트랜잭션 개념은 다른 글에서도 워낙 많은 편이니 생략하도록 하겠다.

 

 

@Transactional 이란?

 

메서드나 클래스에 @Transactional 추가하게 되면

자동적으로 트랜잭션을 시작하고, 정상 여부에 따라 Commit 또는 Rollback 하게 된다. 

 

위에서 얘기한 @Transactional 추가 위치에 따른 처리 차이에 대한 내용이다.

메서드에 추가한 경우: 해당 메서드만 트랜잭션 처리

클래스에 추가한 경우: 모든 메서드의 트랜잭션 처리

 

@Transactional 사용시 주의점

 

다음 내용은 최범균님의 '프로그래밍 초식 : 초심자가 저지르기 쉬운 DB 코딩 실수 3가지' 에서 나온 내용이다.

 

다음과 같은 코드가 있다.

 

1번

    @Transactional
    public void registerMembers(List<Req> reqs) {
        reqs.forEach(req -> {
           try {
               registerService.register(req);
               logDao.insert(createSuccessLog(req, ex));
           } catch (Exception ex) {
               logDao.insert(createFailLog(req, ex));
           }
        });
    }

 

2번

    @Transactional
    public void register(Req req) {
        anyRepository.save(toData(req));
        if (check()) {
            throw new RuntimeException("!");
        }
    }

 

위 '1번'처럼 @Transactional 안에 try catch를 하게 되면 

의도한 대로 동작이 안되게 될 수 있다.

 

loop를 돌면서 register 메서드를 호출하게 되는데 

Exception이 발생하지 않으면 아무 문제가 없는 코드이지만

register 에서 Exception이 발생하게 되면

throw new RuntimeException("!"); 을 호출하면서 트랜잭션이 '롤백' 상태로 바뀌게 된다.

 

이 상태가 되면 나머지 register와 insert는 롤백 상태에서 진행하게 되기 때문에 

아무 의미가 없는 상태가 되어 버린다.

 

그 후 forEach 문이 끝날때 커밋을 시도하게 되는데 지금 트랜잭션 상태가 롤백 상태이기 때문에

커밋을 할 수가 없고, 커밋에 실패하게 된다.

 

여기서 의도는 forEach 를 하면서 정상적인 수행과 실패가 난 사항들을 디비에 따로따로 기록하는 것이 의도였는데,

@Transactional 이 있다보니 의도대로 동작하지 않는 것을 알 수 있다.

 

이 케이스는 중첩된 @Transactional과 try-catch에 대한 내용인데, 

메서드에 @Transactional 설정하고, 안에서 try-catch로 Exception을 처리하고 전파하지 않으면

다음과 같은 내용이 확인 필요하다.

 

1. 중첩된 @Transactional이 있는지

2. 의도하지 않은 롤백 가능성이 없는지

3. 의도한 롤백이 안될 가능성은 없는지 

 

그래서 위 케이스에서는 의도한대로 트랜잭션이 동작하는지 테스트가 필요하다.

 

@Transactional 분리 사용

TBD

 

출처: https://morioh.com/p/a97ace580213

출처: https://goddaehee.tistory.com/167

출처: https://www.youtube.com/watch?v=n85UzIReFjY&t=313s&ab_channel=%EC%B5%9C%EB%B2%94%EA%B7%A0