Welcome! Everything is fine.

INSERT 됐지만 테이블이 안보이는 문제(@Transactional) 본문

TIL

INSERT 됐지만 테이블이 안보이는 문제(@Transactional)

개발곰발 2025. 2. 12. 23:30
728x90

INSERT 됐지만 테이블이 안보이는 문제

댓글 작성 시, 아래와 같이 INSERT문은 제대로 실행된 것 같은데 DB에서는 comment 테이블이 보이지 않는 문제가 있었다.

 

@Transactional을 추가하지 않은 것이 원인이다. 트랜잭션이 자동으로 커밋되지 않아서 데이터가 DB에 반영되지 않았던 것이다. Service 계층에서 DB 작업을 수행할 때는 반드시 @Transactional 을 사용해 트랜잭션을 관리해야한다.

다음과 같이 @Transactional 을 붙인다.

@Transactional
public CommentResponseDto save(Long scheduleId, String email, CommentRequestDto dto) {
    Schedule schedule = scheduleRepository.findByIdOrElseThrow(scheduleId);
    Member member = memberRepository.findByEmailOrElseThrow(email);

    Comment comment = new Comment(dto.getContents(), member, schedule);
    Comment savedComment = commentRepository.save(comment);

    return new CommentResponseDto(
        savedComment.getId(),
        savedComment.getContents(),
        member.getUsername(),
        savedComment.getCreatedAt(),
        savedComment.getModifiedAt()
    );
}

 

이렇게 해도 되지만, 어제 <연관 관계 매핑 세션>에서 튜터님께서 클래스 레벨에 우선@Transactional(readOnly = true)를 사용한다는 것이 기억나 다음과 같이 수정했다. 그리고 지난번 피드백을 다시 보니 다른 튜터님께서도 "트랜잭션 범위를 확실히 하기 위해 DB 업데이트와 관련된 모든 작업을 트랜잭션 내에서 처리하는 것이 좋다."라고 피드백을 남겨주셨다.

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class CommentService {

    private final CommentRepository commentRepository;
    private final ScheduleRepository scheduleRepository;
    private final MemberRepository memberRepository;

    @Transactional
    public CommentResponseDto save(Long scheduleId, String email, CommentRequestDto dto) {
        Schedule schedule = scheduleRepository.findByIdOrElseThrow(scheduleId);
        Member member = memberRepository.findByEmailOrElseThrow(email);

        Comment comment = new Comment(dto.getContents(), member, schedule);
        Comment savedComment = commentRepository.save(comment);

        return new CommentResponseDto(
            savedComment.getId(),
            savedComment.getContents(),
            member.getUsername(),
            savedComment.getCreatedAt(),
            savedComment.getModifiedAt()
        );
    }
}

 

이 문제를 해결하면서 잘 신경쓰지 않았던 부분의 개념을 확실히 익히게 되었다.

  • 클래스 레벨의 @Transactional(readOnly = true) 적용
    • 기본적으로 모든 메서드는 읽기 전용 트랜잭션 사용
    • 변경 감지(Dirty Checking) 비활성화 → 불필요한 데이터 변경 감지 로직 생략 → 성능 최적화
    • 조회 시 @Transactional이 없어도 동작하지만, @Transactional(readOnly = true)를 사용하면 성능이 최적화 되며 Lazy Loading(지연 로딩) 사용 시 트랜잭션 유지가 필요할 수 있음
  • 쓰기 작업에는 @Transactional을 개별적으로 추가해야 함.
    • 메서드 레벨에서 @Transactional을 명시하면, 클래스 레벨의 readOnly = true를 무시하고 데이터 변경이 가능한 트랜잭션으로 동작