[🍊 트랜잭션 주의 사항]
트랜잭션을 사용 시 몇 가지 알아야만 하는 사항이 있다.
이 사항들을 모른다면 트랜잭션을 적용 했음에도 트랜잭션이 적용 되지 않을 수 있다.
이 주의 사항은 실무에서도 반드시 나타나는 문제이며
이 주의사항을 모른다면 몇일씩 고생하는 경우가 생길 수 있다.
[🍊 트랜잭션의 3가지 주의사항]
그렇다면 트랜잭션의 주의사항은 어떤 것들이 있을까?
▶ 트랜잭션 내부 메서드 호출
▶ 접근 제어자 public 외 사용
▶ PostConstruct 사용
여기서 하나라도 포함되어있다면 트랜잭션이 있음에도 불구하고 트랜잭션이 적용이 되지 않는다.
그렇다면 하나씩 알아보자.
[🍊 트랜잭션 내부 메서드 호출]
[스프링DB] 트랜잭션의 작동원리, 프록시 - 기록만이 살 (tistory.com)
[스프링DB] 트랜잭션의 작동원리, 프록시 - 기록만이 살
[만약 이 글을 읽기전 트랙잭션의 원리를 모른다면 이글을 참고하길 바란다] [스프링] 트랜잭션의 이해와 활용,@Transactional 원리 - 기록만이 살길 (tistor [스프링] 트랜잭션의 이해와 활용,@Transaction
thaud153.tistory.com
이 글을 읽기전 트랜잭션의 작동원리를 모른다면 이해하기 어려울 것 이다.
그렇기에 이 글을 본 후 이해하고 글을 읽는 것을 추천한다.
첫 번째로는 트랜잭션 내부 메서드 호출이다.
이것은 무슨 뜻 일까?
쉽게 생각해보자.
트랜잭션은 프록시라는 것을 가지고 있다.
기본적으로 트랜잭션은 타겟이 된 클래스에 프록시를 만들어
프록시를 기반으로 트랜잭션을 만든다.
프록시는 타겟이 된 클래스가 스프링 빈에 등록되어야만 프록시를 생성한다.
하지만 프록시를 거치지 않고 트랜잭션을 호출하면 어떻게 될까?
한번 코드로 보도록 하자.

나는 Service 클래스를 만들었다.
여기에는 3 가지의 메서드가 있다. 하나하나 봐보도록 하자.
public void TxInfo(){
boolean active = TransactionSynchronizationManager.isActualTransactionActive();
log.info("트랜잭션 작동 여부 = {}",active);
}
이 메서드의 경우 트랜잭션이 동작한다면 True 동작하지 않는다면 False라는 상태를 반환하는 메서드 이다.
@Transactional
public void Internal(){
TxInfo();
}
이 메서드의 경우 트랜잭션이 적용된 메서드이며 Internal을 호출한다면
트랜잭션의 정보를 출력하게 하는 메서드이다.
public void external(){
log.info("트랜잭션 메서드 내부 호출");
Internal();
TxInfo();
}
이 부분이 가장 중요하다.
이 메서드인 경우 스프링빈을 거치지 않고 트랜잭션이 걸린 Internal 메서드를 호출하며
트랜잭션의 정보를 출력하는 메서드이다.
[작동]
그렇다면 내가 만약 Internal메서드를 호출한다면
트랜잭션의 상태는 false일까? true일까?

테스트 코드로 봐보도록 하자.
1번 테스트 경우 Service는 이미 스프링 빈으로 등록되어있다.
등록되어 있는 클래스에 Internal 메서드를 호출 시킨다면 트랜잭션의 상태는 어떻게 될 것인가?

트랜잭션이 작동 잘 되는 것을 볼 수 있다.
하지만 2번 메서드의 경우는 어떻게 될까?

2번 메서드의 경우 extenal을 호출한다면 이렇게 동작할 것 이다.
1. 트랜잭션의 작동 여부
2.Internal()을 내부에서 호출 함.

테스트 결과를 실행 해보니 트랜잭션이 false 즉 작동하지 않는 걸 확인 할 수 있다.
왜 이렇게 된 걸까?
[프록시]
한번 생각해보자.
트랜잭션은 기본적으로 프록시를 기반으로 동작한다고 알고 있다.
프록시는 트랜잭션이 걸린 클래스나 메서드 가 스프링 빈에 등록되어 있을 경우 프록시를 생성한다.
하지만 우리는 무엇을 했는가?
트랜잭션이 걸린 Internal()메서드를 스프링을 통해 호출하지 않고
메서드 내부에 통으로 호출 하지 않았는가?

이런식으로 말이다.
이렇게 된다면 트랜잭션이 작동 할 수 있는 프록시를 찾을 수 없고
트랜잭션은 프록시를 찾지 못했기 때문에 트랜잭션이 적용되지 않은 일반 메서드만이 동작하게 된다.

그림으로 본다면 프록시 기반으로 트랜잭션이 동작하는걸 볼 수 있다.
[▶ 트랜잭션 내부 메서드 호출]
즉 트랜잭션 내부 메서드 호출은 스프링을 통해 거치지 않고
호출 됨으로 프록시를 만들 수 없고
트랜잭션은 프록시 기반으로 동작하지만 프록시가 없기 때문에
트랜잭션이 적용되지 않는다.
만약 이 사실을 모른채 트랜잭션을 내부 메서드 호출로 묶어 놓은 로직이 있다면
이 문제를 해결 할 수 없을지도 모른다.
[ 🍊 접근 제어자 public 외 사용 ]
기본적으로 트랜잭션은 접근제어자가 public인 경우에만 적용된다.
그 이유는 여러가지가 있지만 대표적으로는
1. 트랜잭션은 대부분 서비스 로직에 건다.
▶ 즉 비지니스 로직에 넣기 때문에 고객들에게 보여야 함으로 public으로 사용 함.
2. 클래스의 트랜잭션을 걸 경우 모든 메서드에 적용 된다.
▶ 그렇기에 무분별한 트랜잭션의 사용을 막기위해 스프링에서 막아 놓은 것.
더 많은 내용이 있지만 대표적으로 이 두가지의 이유 때문에 스프링이 막아 놓은 것 이다.
한번 확인 해보자.

트랜잭션이 걸린 메서드에 public을 뺏으니 기본 접근 제어자로 동작할 것 이다.

테스트로 확인 해보니 작동이 안하는 것을 볼 수 있다.
[🍊 PostConstruct 사용 ]
이 경우에는 간단한데 @PostConstruct를 사용하면 트랜잭션이 만들어지기 전에
초기화가 되기때문에 적용이 되지 않는다.
'[스프링 DB] > 트랜잭션' 카테고리의 다른 글
[스프링DB] 트랜잭션의 작동원리, 프록시 - 기록만이 살 (1) | 2023.06.28 |
---|---|
[자바 스프링] Test 에서의 트랜잭션 사용 (0) | 2023.06.20 |
[스프링] 트랜잭션의 이해와 활용,@Transactional 원리 - 기록만이 살길 (0) | 2023.06.14 |
[트랜잭션 이란 무엇인가?] - 트랜잭션의 이해 (2) | 2023.06.08 |
[스프링 오류]Could not initialize plugin: interface org.mockito.plugins.MockMaker (alternate: null) 설정오류 (0) | 2023.06.08 |