[Refactor] 산 좋아요 토글 처리로 통일#247
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request refactors the mountain liking functionality by consolidating the existing separate 'like' and 'unlike' API operations into a single toggle mechanism. This change simplifies the API surface, improves consistency across the application, and enhances reliability by incorporating concurrency handling for like operations. The update also includes necessary DTOs, status code updates, and robust unit testing to ensure the new toggle logic behaves correctly under various conditions. Highlights
New Features🧠 You can now enable Memory (public preview) to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
이번 풀요청은 기존의 산 좋아요 등록 및 취소 API를 하나의 토글 API로 통합하고 동시성 요청 발생 시 중복 생성을 방지하기 위해 LikeConflictHandler를 도입하였습니다. 리뷰어는 JPA의 지연 쓰기 특성으로 인해 save 호출 시 동시성 예외가 즉시 감지되지 않는 문제를 지적하며 이를 해결하기 위해 saveAndFlush를 사용하도록 제안했습니다. 또한 이에 맞춰 테스트 코드의 모킹 및 검증 로직도 saveAndFlush를 바라보도록 수정할 것을 권장했습니다.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| private boolean createMountainLike(User user, Mountain mountain) { | ||
| return LikeConflictHandler.handleConcurrentCreate( | ||
| () -> mountainLikeRepository.save(MountainLike.create(user, mountain)), | ||
| () -> log.warn("MountainLike 동시 요청 감지: mountainId={}, userId={}", mountain.getId(), user.getId()) | ||
| ); | ||
| } |
There was a problem hiding this comment.
JPA의 save() 메서드는 트랜잭션이 커밋되거나 플러시되기 전까지 실제 DB에 INSERT 쿼리를 보내지 않고 영속성 컨텍스트에 지연 저장(Write-behind)합니다. 이로 인해 LikeConflictHandler.handleConcurrentCreate 내부의 try-catch 블록이 실행되는 시점에는 DataIntegrityViolationException이 발생하지 않으며, 메서드가 종료된 후 트랜잭션 커밋 시점에 예외가 발생하여 결국 에러 응답이 클라이언트에 반환됩니다.
동시성 요청 시 예외를 정상적으로 감지하고 처리할 수 있도록 save() 대신 saveAndFlush()를 사용해 즉시 DB에 반영하도록 수정해야 합니다.
| private boolean createMountainLike(User user, Mountain mountain) { | |
| return LikeConflictHandler.handleConcurrentCreate( | |
| () -> mountainLikeRepository.save(MountainLike.create(user, mountain)), | |
| () -> log.warn("MountainLike 동시 요청 감지: mountainId={}, userId={}", mountain.getId(), user.getId()) | |
| ); | |
| } | |
| private boolean createMountainLike(User user, Mountain mountain) { | |
| return LikeConflictHandler.handleConcurrentCreate( | |
| () -> mountainLikeRepository.saveAndFlush(MountainLike.create(user, mountain)), | |
| () -> log.warn("MountainLike 동시 요청 감지: mountainId={}, userId={}", mountain.getId(), user.getId()) | |
| ); | |
| } |
| MountainLikeToggleResponse response = mountainLikeService.toggleMountainLike(1L, 10L); | ||
|
|
||
| assertThat(response.liked()).isTrue(); | ||
| verify(mountainLikeRepository).save(any(MountainLike.class)); |
| when(mountainLikeRepository.save(any(MountainLike.class))) | ||
| .thenThrow(new DataIntegrityViolationException("duplicate")); |
There was a problem hiding this comment.
MountainLikeService에서 saveAndFlush()를 사용하도록 변경함에 따라, 테스트 코드의 모킹(when) 메서드도 saveAndFlush를 모킹하도록 수정해야 합니다.
| when(mountainLikeRepository.save(any(MountainLike.class))) | |
| .thenThrow(new DataIntegrityViolationException("duplicate")); | |
| when(mountainLikeRepository.saveAndFlush(any(MountainLike.class))) | |
| .thenThrow(new DataIntegrityViolationException("duplicate")); |
🧾 요약
🔗 이슈
✨ 변경 내용
MountainLikeService:likeMountain/unlikeMountain→ 단일toggleMountainLike로 교체MountainLikeService:LikeConflictHandler적용으로 동시성 예외 처리 방식 통일MountainController:DELETE /{mountainId}/like제거,POST /{mountainId}/like가 toggle 응답 반환하도록 변경MountainLikeToggleResponseDTO 추가 (liked: boolean)ErrorStatus:MOUNTAIN_LIKE_ALREADY_EXISTS,MOUNTAIN_LIKE_NOT_FOUND제거SuccessStatus:MOUNTAIN_LIKE_SUCCESS/MOUNTAIN_UNLIKE_SUCCESS→MOUNTAIN_LIKE_TOGGLE_SUCCESS로 통합MountainLikeServiceTest추가 (토글, 취소, 동시 중복 요청 케이스)✅ 확인