서비스 함수에서 jpa repository에 정의된 쿼리 함수를 호출하는데에서 위와 같은 "No EntityManager with actual transaction available for current thread - cannot reliably process 'remove' call" 오류가 발생하였다.
remove 명령을 실행하는 과정에서 트랜잭션과 관련된 문제가 발생한 것을 확인할 수 있다.
알아보니 이 오류는 스프링 트랜잭션 관련 문제로, 현재 스레드에 실제 트랜잭션이 없기 때문에 'remove' 호출을 신뢰할 수 없다는 것을 의미한 것이었다.
위 오류는 다음 두 가지 상황에서 발생할 수 있는데,
첫번째, 스프링의 트랜잭션 관리 설정이 올바르게 구성되어 있는지?
⇒ 예를 들어, @EnableTransactionManagement 어노테이션이 설정되어 있는지 확인하고, 트랜잭션 관리자가 적절히 설정되어 있는지 확인해야 한다!
두번째, 트랜잭션 어노테이션이 메서드나 클래스에 적용되지 않은 경우
⇒ @Transactional 어노테이션을 메서드나 클래스에 추가하여 트랜잭션을 활성화해서 해결할 수 있다!
나의 경우 두번째에 해당!!!!
나의 코드를 보면, 트랜잭션 경계를 벗어난 상황에서 레포지토리 함수를 호출하고 있다.
스프링에서 트랜잭션은 일반적으로 서비스 레이어에서 관리되는데, 다른 레이어(컨트롤러)에서 트랜잭션 경계를 벗어나서 호출하면 이러한 오류가 발생할 수 있다.
따라서 트랜잭션 범위 내에서 해당 호출을 수행하도록 코드를 구성해야 한다!
아래와 같이 해결하였다.
이전에 비슷한 오류가 발생하였을 때, 레포지토리 함수 자체에 @transactional 어노테이션을 추가하여 해결한 적이 있다.
그렇다면, 레포지 함수 자체에 어노테이션을 추가하는 것과, 이를 호출하는 서비스 함수에 어노테이션을 추가하는 것 중 어느것이 더 적절한 방법일까?
일반적으로 서비스 계층에서 @Transactional 어노테이션을 추가하는 것이 더 좋은 설계이다!!!
이유는 다음과 같다
- 레이어 간의 역할 분리 : 서비스 계층은 비즈니스 로직을 처리하는 데 책임이 있으며, 트랜잭션 관리 역시 서비스 계층에서 이루어져야 한다. 따라서 트랜잭션 관리는 서비스 계층의 역할이며, 레포지토리는 데이터 액세스에 집중해야 한다. 이를 위해 트랜잭션 관리는 서비스 계층에 위임하는 것이 좋다!
- 트랜잭션 경계의 명확성: 서비스 계층에서 @Transactional 어노테이션을 추가하면 트랜잭션의 범위가 서비스 메서드의 호출과 일치하게 된다. 이는 트랜잭션 경계를 명확하게 설정하여 예기치 않은 동작을 방지하는 데 도움이 된다.
- 트랜잭션 관리의 유연성: 서비스 계층에서 트랜잭션 관리를 담당하면 여러 레포지토리 메서드를 호출하는 복잡한 비즈니스 로직에서도 단일 트랜잭션으로 묶을 수 있다. 이는 일관된 데이터 처리와 롤백을 보장하여 데이터의 무결성을 유지하는 데 도움이 된다.
따라서, 가능하다면 레포지토리에서 직접 @Transactional 어노테이션을 추가하는 대신 해당 함수를 호출하는 서비스 계층에서 @Transactional 어노테이션을 추가하는 것이 좋다.
이렇게 하면 역할과 책임이 분리되며, 트랜잭션 관리가 명확하고 유연하게 이루어질 수 있다!!!
"트랜잭션 관리를 명확히 하기!!!"
'Web Application > Backend' 카테고리의 다른 글
인터페이스? API? 인터페이스 개념 확실히 알기! (0) | 2023.11.02 |
---|---|
RESTful API 개념 확실히 잡기!!! (0) | 2023.10.10 |
[스프링부트] 스프링부트 Secrity 기본 구성 구현하기 (페이지 강제 접근 막기) (0) | 2023.09.20 |
[스프링부트] Pageable 인터페이스로 페이징 기능 구현하기 (0) | 2023.07.06 |
스프링부트 test code 작성해보기 (0) | 2023.07.05 |