- 클래스 단위로 설정 가능
- 클래스 단위로 설정해두고,
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
우선순위
- 클래스 메소드
- 클래스
- 인터페이스 메소드
- 인터페이스
- 위와 같이 공통적인 트랜잭션 규칙은 클래스에, 특별한 규칙은 메서드에 선언하는 식으로 구성할 수 있음.
- 인터페이스 보다는 클래스에 적용하는 것을 권고
- 인터페이스 기반 프록시에서만 유효한 트랜잭션이 설정되기 때문
- 자바 어노테이션은 인터페이스로부터 상속되지 않기 때문에 클래스 기반 프록시 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 정리하기