Skip to content

[Refactor/Mod] schedule 수정 메서드 리팩토링 및 영속성 컨텍스트 충돌 문제 해결 #217

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 2, 2025

Conversation

jjjh02
Copy link
Contributor

@jjjh02 jjjh02 commented May 2, 2025

문제 상황

2025-05-02T20:27:23.753+09:00 ERROR 1 --- [ontime-back] [nio-8080-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.springframework.orm.ObjectOptimisticLockingFailureException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [devkor.ontime_back.entity.PreparationSchedule#123e4567-e89b-12d3-a456-326614174011]] with root cause

org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [devkor.ontime_back.entity.PreparationSchedule#123e4567-e89b-12d3-a456-326614174011]

수정한 부분

  • modifySchedule: Schedule 객체 내부에 updateSchedule 메서드에서 dto를 받아옴 -> 캡슐화 향상
  • createSchedule: ScheduleAddDto에서 toEntity를 사용해서 Schedule 객체 생성
    • DTO → Entity 변환 책임을 DTO에 위임 (책임 분리)
  • ObjectOptimisticLockingFailureException 발생
    • preparationSchedule이랑 schedule이 연결되어있어서 preparationSchedule을 삭제하고 schedule을 삭제하는데, PreparationSchedule을 삭제했지만, Hibernate는 아직도 내부적으로 해당 엔티티들을 영속성 컨텍스트에 들고 있어서 마지막 flush() 시점(= 트랜잭션 커밋 직전)에 이미 삭제된 row에 대해 또 삭제 시도 → 충돌 발생
    • 해결방법) flush() 호출하여 영속성 컨텍스트에서 해당 엔티티들도 “삭제됨”으로 인식하게 됨

@JunbeomKoreaUniv
Copy link
Contributor

오 이해했습니다. 하드 딜리트를 하다보니까 이런 문제도 발생하는군요 신기하네요

Comment on lines 90 to 92
preparationScheduleRepository.deleteBySchedule(schedule);
preparationScheduleRepository.flush();
scheduleRepository.deleteByScheduleId(scheduleId);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

기존에 preparationSchedule을 DB에서 삭제한 뒤, preparationSchedule이 영속성 컨텍스트에 삭제된 내용이 반영이 안된 상태에서 schedule을 DB에서 삭제해서 발생한 오류고, 이를 flush를 통해 영속성 컨텍스트에 반영시켜 정상 삭제가 되게 하는 것으로 이해했습니다.

그런데! 저희 PreparationSchedule엔티티를 보면 Schedule에 CASCADE 설정이 돼있습니다. 그래서 Scheduledㅡㄹ 삭제할 때 preparationSchedule을 직접 삭제하는게 아니라 Schedule만 삭제하면 CASCADE로 삭제라는 행동이 영속성 컨텍스트로 전파가 돼서 preparationSchedule도 삭제되는 것 같습니다.

로컬에서도 테스트해보았는데 90,91번 라인을 지워도 정상동작하는 것 같습니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그렇네요! ON DELETE CASCADE가 적용되어 schedule 테이블의 행이 삭제되면 그 schedule_id를 참조하고 있는 preparation_schedule의 행들도 DB가 자동으로 같이 삭제하네요. 저도 로컬에서 테스트해서 확인해보니 잘 작동합니다!

deleteSchedule에

        cancelAndDeleteNotification(notification);
        notificationScheduleRepository.flush();

notificationSchedule 관련해서도 동일한 방식으로 간결하게 정리할 수 있지 않을까 하는 생각이 드는데
혹시 preparationSchedule과는 좀 다를까요?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

음 NotificationSchedule엔티티에 CASCADE설정이 안돼있어서 CASCADE설정 추가하면 deleteSchedule메서드 더 얇게 가져갈 수 있을 것 같네요. 이거 나중에 반영하겠습니다.~

확실히 리뷰하면서 더 여유있게 보니까 제가 썼던 코드에서 놓쳤던 부분도 보이는 것 같습니다. 굳 수고하셨어요

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵넵 봐주셔서 감사합니당 ~

@JunbeomKoreaUniv JunbeomKoreaUniv merged commit 82ef5ce into main May 2, 2025
2 checks passed
@jjjh02 jjjh02 mentioned this pull request May 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants