Why?

Spring - private 메서드에 @Transactional이 적용될까?

Cold Bean 2023. 4. 15. 18:45
728x90

배경

오늘도 어김없이 private 메서드에 @Transactional 애너테이션을 적용했는데 오늘따라 SonarLint가 눈에 띄었다.

		@Transactional
    private void createRoles(Member member) {
        List<String> roles = authorityUtils.createRoles(member.getEmail());
        if (roles.isEmpty()) {
            throw new BusinessLogicException(ExceptionCode.MEMBER_ROLE_DOES_NOT_EXISTS);
        }
        member.setRoles(roles);
    }
Non-public methods should not be "@Transactional"
 
Bug
 
Major
java:S2230
 
Marking a non-public method @Transactional is both useless and misleading because Spring doesn’t "see" non-public methods, and so makes no provision for their proper invocation. Nor does Spring make provision for the methods invoked by the method it called.
Therefore marking a private method, for instance, @Transactional can only result in a runtime error or exception if the method is actually written to be @Transactional.

Noncompliant Code Example

@Transactional  // Noncompliant
private void doTheThing(ArgClass arg) {
  // ...
}

해석해 보면 Spring은 private 메서드를 인식하지 않고 적절한 호출을 하지 않기 때문에 @Transactional 애너테이션을 적용하는 것은 권장하지 않는다고 한다.

 

Why?

@Transactional 애너테이션은 private 메서드에 적용할 수 없다. 그 이유는 AOP가 프록시 패턴을 사용하기 때문이다.

Spring은 AOP를 사용해서 @Transactional 애너테이션을 처리하고, 이 과정에서 동적으로 프록시 객체를 생성한다. 생성된 프록시 객체는 원래의 Bean 객체를 대신해서 호출된다.

 

private 메서드나 private 필드는 해당 클래스에서만 접근 가능하기 때문에 외부에서 접근해서 프록시 객체를 생성할 수 없게 되는 것이다. 그래서 @Transactional 애너테이션을 가지고 있는 private 메서드에 접근하려고 해도 프록시 객체를 생성할 수 없기 때문에 해당 애너테이션을 무시하게 된다.

 

하지만 @Transactional 애너테이션이 적용된 public 메서드에서 private 메서드를 호출하면 해당 private 메서드에도 Transaction이 적용된다.

@Service
@RequiredArgsConstructor
public class ExampleService {
    
    private final ExampleRepository exampleRepository;

    @Transactional
    public void publicMethod() {
        ...
        privateMethod();
        ...
    }

    private void privateMethod() {
        ...
        exampleRepository.save(example);
        ...
    }
}

 

@Transactional

Spring에서 @Transactional 애너테이션은 메서드 호출 시 트랜잭션을 적용해 준다. 해당 메서드 실행 도중 예외가 발생하면 그동안 수행되었던 작업을 롤백해 준다. @Transactional 애너테이션을 사용해서 리소스를 안전하게 처리할 수 있다.

 

AOP(Aspect-Oriented Programming)

AOP는 객체 지향 프로그래밍을 보완하기 위한 프로그래밍 기법이다. AOP의 핵심은 관심사를 분리하는 것이다. 공통으로 사용되는 기능(로깅, 보안, 트랜잭션, 캐싱 등)을 모듈화하고 캡슐화해서 핵심 비즈니스 로직과 분리시킨다.

 

마무리

  1. private 메서드에는 @Transactional 애너테이션이 적용되지 않는다.
  2. @Transactional 애너테이션이 적용된 publica 메서드가 호출한 private 메서드에는 Transaction이 적용된다.
728x90