Serivce 단에서 간단하게 엔티티의 필드 값을 수정하는 메서드를 작성하면서 나는 변경 감지를 배웠기 때문에 repository의 save 메서드를 호출하지 않아도 DB에 저장된다고 생각했다.
@Service
@RequiredArgsConstructor
public class MemberService {
private final MemberRepository memberRepository;
public void editProfile(Long memberId, MemberDto memberDto) {
Optional<Member> result = memberRepository.findById(memberId);
Member member = result.get();
member.editProfile(memberDto.getNickname(), memberDto.getBojId(), memberDto.getThumbPhoto());
// memberRepository.save(member);
}
...
}
하지만 내 생각과 다르게 이 케이스에서 DB에 반영되지 않았다.
이와 관련해서 알아본 결과 @Transactional을 붙여줘야 해결될 수 있는 문제였다.
@Transactional 어노테이션은 메서드가 트랜잭션 내에서 실행되도록 지정하는 어노테이션으로, 해당 메서드 내의 모든 DB 변경 작업은 하나의 트랜잭션으로 묶인다.
이때, JPA에서는 영속성 컨텍스트를 사용하여 엔티티의 상태를 관리한다.
트랜잭션 내에서 엔티티를 조회하거나 수정하면, 해당 엔티티는 영속성 컨텍스트에 관리된다.
따라서 @Transactional 어노테이션을 사용하면서 엔티티의 상태가 변경되면 자동으로 변경 감지가 발생하여 DB에 반영되므로 memberRepository.save(member); 코드를 주석 처리하셔도 무방하다.
변경된 코드는 다음과 같다.
@Service
@RequiredArgsConstructor
public class MemberService {
private final MemberRepository memberRepository;
@Transactional
public void editProfile(Long memberId, MemberDto memberDto) {
Optional<Member> result = memberRepository.findById(memberId);
Member member = result.get();
member.editProfile(memberDto.getNickname(), memberDto.getBojId(), memberDto.getThumbPhoto());
// memberRepository.save(member);
}
...
}
이와 관련해서 @Transactional을 데이터의 변경, 추가, 삭제 등이 있을 때 적용하지 않을 경우 생기는 문제에 대해 알아보았다.
- 데이터의 일관성 문제
트랜잭션이 시작되고 데이터베이스 작업을 실행하는 동안 예외가 발생하면, @Transactional이 없는 경우에는 각각의 데이터베이스 작업이 독립적으로 실행됩니다. 따라서 일부 작업은 성공하고 일부 작업은 실패할 수 있으며, 데이터 일관성이 깨질 수 있다. @Transactional이 적용된 메서드에서는 예외가 발생하면 해당 트랜잭션이 롤백되어 모든 데이터베이스 작업이 취소되고, 일관성 있는 상태를 유지한다.
- 효율성 문제
트랜잭션이 없는 상태에서 여러 개의 데이터베이스 작업을 하나의 작업으로 묶지 않으면, 각각의 작업마다 별도의 트랜잭션을 열고 닫는 오버헤드가 발생한다. 트랜잭션은 데이터베이스 작업을 논리적 단위로 묶어서 한 번에 처리하기 때문에 더 효율적인 데이터베이스 사용을 가능하게 한다.
정말 유익한 글이었습니다.