[Spring] @Transactional

이준우·2024년 4월 14일
0
  • 클래스 단위로 설정 가능
    • 클래스 단위로 설정해두고, readOnly=ture 옵션은 메서드에 달아두는 것도 나쁘지 않다.
      @Service
      @RequiredArgsConstructor
      @Transactional
      public class MemberService {
      
      	private final MemberRepository memberRepository;
      	private final JwtService jwtService;
      	private final RefreshTokenService refreshTokenService;
      	private final HttpServletRequest request;
      	private final HttpServletResponse response;
      
      	public void register(MemberServiceDto memberServiceDto) {
      		Member member = findByEmail(memberServiceDto.getEmail());
      
      		member.register(memberServiceDto);
      
      		String refreshToken = jwtService.createRefreshToken();
      
      		jwtService.setRefreshTokenHeader(response, refreshToken);
      		refreshTokenService.updateToken(member.getEmail(), refreshToken);
      	}
      
      	public String getMemberByEmail() {
      		String accessToken = jwtService.extractAccessToken(request).orElseThrow(NotFoundTokenException::new);
      		return jwtService.extractEmail(accessToken).orElseThrow(NotFoundEmailException::new);
      	}
      
      	@Transactional(readOnly = true)
      	public Member findByEmail(String email) {
      		return memberRepository.findByEmail(email).orElseThrow(NotFoundMemberException::new);
      	}
      
      	@Transactional(readOnly = true)
      	public Member findById(Long id) {
      		return memberRepository.findById(id).orElseThrow(NotFoundMemberException::new);
      	}
      }
      
  • @Transactional이 선언되면 해당 클래스에 트랜잭션이 적용된 프록시 객체 생성
  • 프록시 객체는 @Transactional이 포함된 메서드가 호출될 경우, 트랜잭션을 시작하고 Commit or Rollback을 수행
    • CheckedException or 예외가 없을 경우 Commit
    • UncheckedException이 발생하면 Rollback

우선순위

  1. 클래스 메소드
  2. 클래스
  3. 인터페이스 메소드
  4. 인터페이스
  • 위와 같이 공통적인 트랜잭션 규칙은 클래스에, 특별한 규칙은 메서드에 선언하는 식으로 구성할 수 있음.
  • 인터페이스 보다는 클래스에 적용하는 것을 권고
    • 인터페이스 기반 프록시에서만 유효한 트랜잭션이 설정되기 때문
    • 자바 어노테이션은 인터페이스로부터 상속되지 않기 때문에 클래스 기반 프록시 or AspectJ 기반에서 트랜잭션 설정을 인식할 수 없음.

트랜잭션 모드

  • Proxy Mode와 AspectJ Mode가 있다
  • Proxy Mode(default)
    • 반드시 public 메서드에 적용되어야 함
    • Non-Public 메서드에 적용하고 싶으면 AspectJ Mode를 고려해야 함
  • @Transactional이 적용되지 않은 Public Method에서 @Transactional이 적용된 Public Method를 호출할 경우, 트랜잭션이 작동하지 않는다.

설정

다중 Transaction Manager

  • 필요에 따라 다수의 독립된 트랜잭션 매니져를 사용할 수 있음
  • @Transactional의 value 속성에 사용할 Platform TransactionManager를 지정하면 됨
    • Platform TransactionManager
      • Spring에서 제공하는 트랜잭션 관리 인터페이스
      • 구현체에는 JDBC, 하이버네이트 등, 트랜젝션이 실제 작동할 환경이 존재
      • 알맞은 PlatformTransaction Manager 구현체가 정의되어 있어야 함
  • value 속성에 Bean의 id 또는 qualifier 값을 지정해서 등록

테스트 환경

  • 테스트 메서드에 @Transactional 을 사용하면 트랜잭션으로 감싸지며, 메서드가 종료될 때 자동으로 롤백
  • id는 자동으로 롤백되지 않음
    • ID 생성 전략 중 하나인 AutoIncrement 옵션은 트랜잭션의 범위 밖에서 동작하기 때문
      • 동시성 때문
      • 각 트랜잭션이 다른 사람의 회원가입 트랜잭션 성공 여부를 기다렸다가 id를 부여받기엔 얼마나 기다려야할 지 모르기 때문

@Transactinal을 중첩해서 사용

  • 자식 트랜잭션은 부모 트랜잭션과 동일
  • @Transactional의 propagation(전파) 기본 설정은 REQUIRED여서 부모 트랜잭션 내부에 자식 트랜잭션이 실행되는 경우, 부모 트랜잭션에 자식 트랜잭션이 합류한다. 부모 트랜잭션이 없는 경우에만 새로운 트랜잭션이 생성된다.

Reference


data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAMAAABF0y+mAAAAP1BMVEVHcEz/Wkv/Wkr/Wkr/Wkr/Wkr/Wkr/Wkr/Wkr/W0z/Wkr/W0r/Sjf/2Nb/6ef/cmX/VEP/rqj/////yMT/jYMQjqqgAAAADHRSTlMAL4O/5/ld7P8U3TpibdPBAAAAxklEQVR4AWyRgQ7FEAwAC7aywsz/f+vbarHu2SWRxkVygIHSxjpnjVbwz7LiYF1A4gO+CP5xG05ss5utx088y/AtA3f2mUgszNV83yGmXDAlLDnF+0YAioey1xrpqPWgWOteeFOB7rKdW7TfS+tSg0GGWqOxdIcGLHZK6S08dSw4HJwtKeODe8krqEhphWzcMrAcNGzOw3GQlpJISg1KHqxVHlXj+eag9Xn4OWh5f1n5DYgQUYY3svElE3wJDF/SJJyo8WYHAN28FxGg0dDcAAAAAElFTkSuQmCC

[Spring] @Transactional의 이해

Transactional 어노테이션

[Spring] Transactional Propagation 정리하기

profile
잘 살고 싶은 사람

0개의 댓글