Notion - @Transactional Duplicate entry 이슈
문제
Duplicate entry '325' for key 'token.UK_c56184j4djjqx16jwprg167qp'
이전에 개발하던 개인 프로젝트에서 @Transactional에 대한 이해가 부족하여 발생한 문제이다.
아래는 문제가 발생한 코드의 일부이다.
`UserService`
@Transactional
public Long userLogin(UserForm userForm) {
User user = userRepository.findByEmail(userForm.getEmail())
.orElseThrow(InvalidSigninInformation::new);
if(!scryptPasswordEncoder.matches(userForm.getPassword(), user.getPassword())) {
throw new InvalidSigninInformation();
}
if(!user.getTokens().isEmpty()) {
tokenRefresher.removeRefreshToken(user);
}
tokenRefresher.addRefreshToken(user);
return user.getId();
}
`TokenRefresher`
@Transactional
public void removeRefreshToken(User user) {
tokenRepository.deleteByUserId(user.getId());
}
@Transactional
public void addRefreshToken(User user) {
user.addToken(jwtTokenProvider.createRefreshToken(user.getId()));
}
서로 다른 클래스에서 각 메서드에 @Transactional을 사용하였고, `removeRefreshToken` 동작과 `addRefreshToken`가 같은 트랜잭션 내에서 동작하여 발생한 문제이다.
@Transactional을 기본적으로 Required 전파레벨을 사용하는데, 이는 기존 사용하던 트랜잭션이 있다면, 그 트랜잭션에 합류하여 작업을 같이 처리한다.
위 코드에서 볼 수 있다시피 기본 전파레벨을 선택했고 이로인해 `removeRefreshToken` 이 적용되지 않은 채로 `addRefreshToken` 을 통해 새로운 Token을 추가하려 했기 때문에 문제가 발생한 것이다.
해결
전파레벨 설정
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void removeRefreshToken(User user) {
tokenRepository.deleteByUserId(user.getId());
}
@Transactional
public void addRefreshToken(User user) {
user.addToken(jwtTokenProvider.createRefreshToken(user.getId()));
}
`REQUIRES_NEW` 옵션은 기존 트랜잭션이 존재하더라도 새로운 트랜잭션을 만들어 처리하기 때문에, 삭제 작업이 있을 경우 처리하여 적용되도록 할 수 있다.
정리
@Transactional을 공부하고 나니 이해하기도 수월했고 해결하기도 쉬운 문제였다.
열심히 정리해보았으니 @Transactional에 대한 더 자세한 내용이 필요하다면, 아래 글을 참고하길 바란다.
'트러블슈팅' 카테고리의 다른 글
[오류를 잡아보자] Spring security에서 DeferredResult 처리 시 401 Unauthorized (0) | 2024.04.05 |
---|---|
[오류를 잡아보자] NoClassDefFoundError / ClassNotFoundException: org.hibernate.dialect.MySQL57Dialect (2) | 2024.01.28 |
Kakao Login 시 401 Unauthorized (1) | 2024.01.26 |
CreatedDate, LastModifiedDate 사용 시 값이 들어가지 않는 이슈 (0) | 2024.01.21 |
[오류를 잡아보자] 생성자 바인딩 이슈 (Cannot resolve parameter names for constructor) (0) | 2024.01.17 |