24-05-31 Spring 팀 프로젝트 (4)
오늘도 프로젝트 막바지였기 때문에 정신없이 바쁜 하루였다. 생각보다 코드 작성에 시간이 오래 걸렸고 여러가지 목표했던 것을 포기해야하는 것들도 생기기도 했다.
이번이 사실상 첫 프로젝트이기 때문에 시행착오 중 하나라고 생각하면 될 것 같다. 다음 프로젝트에는 더 잘할 수 있을 것 같다.
오늘도 프로젝트 진행중에 있었던 예외 발생에 대해 간략하게 적어보았다.
1. 다시 마주한 LazyInitializationException 예외
오늘도 코드를 작성하고 테스트하던 도중에 LazyInitializationException과 또 마주치게 되었다. 이미 한 번 봤었던 오류이기 때문에 쉽게 이유를 알아낼 수는 있었다.
하지만 내가 예상했던 방식으로 코드가 작동하지는 않아서 더 자세히 들여다보게 되었다.
@OneToMany(mappedBy = "post")
var comments: MutableList<Comment> = mutableListOf()
위는 Post의 엔티티 중 일부이다. Comment와 Post는 양방향 연관관계를 맺고있고, 연관관계의 주인은 Comment이다. Post쪽이 일대다 연관관계를 맺고있다. 즉, 위의 comments 에는 Post와 연관관계를 맺고있는 Comment들이 들어있게 된다.
내가 하고 싶었던 것은 comments.size로 특정 Post에 달린 Comment의 갯수를 세고싶었던 것이었다. 하지만 comments.size를 그냥 사용했더니 LazyInitializationException이 발생했다.
나의 단순한 생각으로는 Comment 안의 내용물들은 조회하지 않고 오로지 갯수만 세는 것이기 때문에 이런 지연 초기화로 인한 문제가 없을 줄 알았다.
하지만 단순히 컬렉션의 크기를 구하려고 할때에도 초기화가 발생하게 된다.
따라서 문제를 해결하려면 함수 전체에 트랜잭션을 유지시켜주거나, 즉시 로딩으로 설정을 바꿔주면 되기는 하다. 하지만 단순히 갯수를 세려고 Comment안의 내용물들을 모두 불러오는 것은 비효율적이라는 생각이 들었다.
Comment 저장소에 가서 Post의 Id를 가지고 단순히 Count만 쿼리로 뽑아내는 방법으로도 코드를 작성해보았고 잘 작동하였다. 위의 두 가지 해결책보다는 더 효율적인 해결책이라고 생각했는데 실제로 이 방법으로 코드를 구현하지는 않았다.
Post 엔티티에 commentCount라는 행을 하나 추가하고 댓글일 달리거나 삭제될 때 숫자를 더하거나 빼는 방식으로 구현하자는 이야기가 팀원에게서 나왔고 결국 이 방법을 택하게 되었다. Comment와 연관관계를 맺고 삭제될 때 같이 삭제되도록 제약조건을 걸어놓은 것이 Post 하나밖에 없기 때문에 Comment를 직접 삭제하지 않는 이상에야 삭제될 일이 없었기 때문에 카운트가 꼬일 일은 없기 때문이다. (Post가 지워지면서 연관있는 Comment들 모두 지워져도 어차피 Post도 지워지기 때문에 카운트가 어찌되든 상관이 없다.)
회원이 탈퇴해서 그 회원이 남긴 댓글들도 모두 지워야한다와 같은 경우가 생긴다면 조금 문제가 생길 수 있는데, 이 부분도 회원이 탈퇴한다고해도 댓글들을 모두 남기는 게 정책이었기 때문에 크게 문제가 되지 않는다.(그리고 프로젝트 시간이 조금 부족해서 회원 탈퇴 기능 자체가 현재 없기도 하다.)
따라서 현재 상황에서는 위의 방법이 가장 효율적이라고 생각해서 선택하여 적용하게 되었다. 추후에 어플리케이션이 크게 변경되어야할 경우에도 위와 같은 방법이 효과적인가에 대해 분명 고민해봐야할 것 같긴 하다. 현재 단계에서는 아쉽지만 일단 잘 구현해보았고 고민해보았다는 것으로 만족해야할 것 같다.
2. 오늘 배운 것
- 프로젝트 코드를 작성하다가 머리가 좀 아플 정도 였는데 그래도 잘 돌아가게 만들었기 때문에 만족한다. 코드가 많이 지저분한 부분은 아쉽긴 한데 차차 고쳐나갈 수 있을 것 같다.