Kotlin
중복 데이터로 인한 Single{}의 IllegalArgumentException
keep it simple
2023. 8. 23. 21:08
문제
- 운영하는 프로젝트 기능 중에 익명 게시판이 있다. 한 게시글에 익명인 사람이 여러개의 댓글을 올려도 같은 익명 닉네임으로 표시해야한다. 익명 댓글을 입력하는 비즈니스 로직은 밑과 동일하다. 한 게시글에 같은 유저가 두개의 익명 닉네임을 가지고 있으면 안된다.
- 익명 여부를 포함한 게시글을 저장한다.
- 익명 닉네임(Community_Nickname) 테이블에서 댓글 작성자가 해당 게시글을가진 닉네임이 존재하는지 확인한다.
- 존재하지 않을 경우 익명 닉네임(Community_Nickname) 테이블에 작성자의 ID와 게시글의 ID를 저장한다.
- 문제가 된 케이스는 조회할 떄 getNickname()을 사용한다. 익명의 게시글이 두개일 경우 single{ } 함수에 의해 IllegalArgumentException 예외를 뱉는다.
fun getNickname(userId: Long) = this.nicknames.single{it.user.id = userId}.nickname
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException: Collection contains more than one matching element.] with root cause
java.lang.IllegalArgumentException: Collection contains more than one matching element.
해결 방법
- Redis를 사용해서 1초내에 연속된 건을 중복 방지를 할 수 있다.
- DB에 그룹으로 유니크 값을 생성해서 중복된 데이터를 저장시 예외를 던지도록 처리할 수 있다.
ALTER TABLE Community_Nickname ADD UNIQUE (userId,communityId);
- Single{} 대신에 First{}를 사용하면된다. 다중이여도 Collection에서 첫번째 데이터를 가져오기 때문에 IllegalArgumentException: Collection contains more than one matching element. 예외가 터지지 않는다.
fun getNickname(authId: Long) = this.nicknames.first { it.auth.id == authId }.nickname
내가 선택한 방법은 마지막 방법이다. Redis 같은 경우에는 기능의 중요도에 비해 리소스가 많이 든다. DB에 유니크 값 생성하는 경우에는 만약 테이블 마이그레이션이나 변경이 있는 경우 관리가 어려울 것 같다. 그래서 first{}를 사용함으로써 기능의 목적인 익명은 보장되면서 관리하기 편리해서 마지막 방법을 선택했다.