springboot

[SpringBoot] @Transactional을 정확하게 알아보자

inhooo00 2025. 1. 15. 22:26

📍Transaction이란?

필자는 단순하게 transaction을 데이터베이스에서 진행되는 하나의 단위라고만 알고 있었다. 이 transaction을 좀 더 자세하게 알아보자.

transaction은 여러 작업을 하나의 논리적 단위로 묶어서 실행한다. 
즉 1번부터 4번까지의 작업(여러 작업)을 하나로 묶어 문제없이 모두 성공하면 commit을, 중간에 문제가 발생했을 때 모든 작업을 롤백(rollback)한다.
이렇게 하면 모든 작업이 수행되거나 or 모두 수행되지 않기 때문에 데이터 일관성을 유지할 수 있다.

 

 

 

📍프록시란?

transaction과 함께 나오는 개념 중에 프록시란 개념이 있다.

실제 객체에 대한 대리 객체를 생성하여, 호출을 가로채고 추가 작업(로깅, 트랜잭션 등)을 수행한 후 실제 객체에 전달하는 기술.

@Transactional이 내부적으로 프록시를 사용한다고 알고 넘어가면 된다.

즉 이 어노테이션을 붙이게 된다면, 어노테이션이 적용된 클래스 또는 메서드 자체가 프록시 객체로 생성되는 것이다.

 

 

 

📍@Transactional 동작 과정

1. @Transactional 메서드 호출 감지

TransactionInterceptor가 메서드 호출을 가로채 트랜잭션을 준비한다.

이 단계에서 트랜잭션 시작, 커밋, 롤백의 필요성을 결정한다.

 

2. Transaction manager 결정

메서드와 클래스의 트랜잭션 속성에 따라 적절한 트랜잭션 메니저를 선택한다.

필자는 보통 JPA를 사용하니 JPA Transaction Manager가 사용된다.

 

3. 커넥션 생성

위에서 만든 Manager안에 있는 데이터 소스를 통해 커넥션(데이터베이스 연결)을 생성한다. 

 

4. 트랜잭션 시작

데이터베이스 수준에서 트랜잭션이 시작되며, 이후의 모든 SQL 작업은 트랜잭션에 포함된다.

 

5. 트랜잭션 동기화 매니저에 커넥션 저장

트랜잭션동안 동일한 커넥션을 하나의 스레드에서 일관되게 사용하도록 보장한다.

 

6. 타겟 메서드 호출

이 모든 작업이 완료되어야 우리가 작성한 비지니스 로직이 실행된다.

 

 

 

📍@Transactional 사용 시 주의점

프록시 내부 호출시 주의할 부분이 있다.

 

1. 같은 클래스 내부 메서드 호출 시 @Transactional 미적용

스프링의 @Transactional은 프록시 객체를 통해 트랜잭션 경계를 설정한다.

이때 프록시 객체는 외부에서 호출된 메서드만 가로채서 트랜잭션 로직을 실행한다. 

만약 같은 클래스 내에서 @Transactional이 설정된 메서드를 호출하면, 프록시를 거치지 않으므로 트랜잭션이 동작하지 않는 문제가 발생하게 된다.

해결 방법으로는 클래스를 분리하면 된다 -> ex) service + controller 와 비슷

 

2. @Transactional은 private 메서드에 적용되지 않음.

@Transactional은 프록시 객체에서 트랜잭션 경계를 관리한다.

스프링에서 프록시는 기본적으로 CGLIB 라이브러리를 통해 대상 클래스의 서브 클래스를 생성한다.

하지만 private 메서드는 서브 클래스에서 호출할 수 없기 때문에, @Transactional을 적용해도 동작하지 않게 된다.

 

 

 

📍결론

1. 빈 생성 시, @Transactional 어노테이션이 있으면, 프록시 객체가 빈으로 등록된다.
2. 스프링이 제공하는 선언적 트랜젝션(클래스나 메서드에 어노테이션) 관리를 통해, 서비스 레이어에 트랜잭션 관련된 코드 혹은 특정 기술에 종속된 코드를 분리할 수 있다.

 

 

 

++

AOP는 무슨 뜻인가요?

  • Aspect-Oriented Programming, 즉 관점 지향 프로그래밍이라고 한다.
  • 이건 반복적으로 쓰는 코드를 깔끔하게 관리하기 위해 사용하는 방법이다.
  • 쉽게 말해 객체 지향 프로그램을(OOP)을 보완하기 위해 쓰이는 개념
  • 때문에 @Transactional과 AOP는 때놓을 수 없다.