본문 바로가기
내가 배운 것들/문제 해결

[SpringBoot] JPA를 이용해 랜덤한 하나의 레코드만 가져오려면 어떻게 해야할까?

by Zabee52 2021. 12. 9.

랜덤 레코드 가져오기

고민이 많았던 부분이다. 미니프로젝트 진행 중 테이블 전체 중 하나의 랜덤 column만 가져와야하는 요구사항이 있어서 어떻게 가져와야할지 생각을 많이 했다.

요구사항은 다음과 같았다.

 

   1. 랜덤한 게시글 1개를 사용자에게 보내준다.

   2. 이렇게 보고 난 글은 랜덤조회 방법으로 다시는 볼 수 없다.

 

사실 내가 만든 요구사항이었다. 되는지 안 되는지도 모르고 막 질러놨더니 그 업보가 나에게 돌아왔다. 사람은 말을 아끼고 살아야 한다.

사랑만 돌아온다면 좋았을텐데.....

하지만 내뱉은 말은 주워담을 수 없는 법. 그래서 했다.

처음에 생각했던 방법은 다음과 같았다.

 

   1. 이미 읽은 게시글을 제외한 게시글을 대상으로 findAll() 한다.

   2. 1.의 결과물 중 랜덤한 하나의 레코드만 가져온다.

   3. 그 게시글을 읽음 처리한다.

 

이렇게 하면 무조건 된다. 심플한 방법이다. 동시에 쓰면 안 되는 방법이다. 단 하나의 레코드를 가져오기 위해 DB를 Full-Scan 하는 것은 DB에 큰 부하를 주는 일이기 때문이다. 그래서 다른 방법을 고민했다. 하지만 답은 쉽게 나오지 않았다.

 

생각해보면 이런 기능은 누군가가 분명 구현을 했을 것이다. 인터넷에 없는게 말이 안 된다. 그래서 인터넷을 찾아봤고, 해답을 구했다. 같은 고민을 공유한 선배개발자일지도 모르는 누군가에게 동질감과 더불어 감사의 뜻을 전하고 싶다.

 

Fetch random records using Spring data JPA

I want to fetch random records using Spring data JPA. I was using @Query for the same.But it is taking a long time. @Query("select que from Question que order by RAND()") public List<Question>

stackoverflow.com

 

게시글이 사라질지도 모르니 한 마디로 내용을 요약하자면, 페이징 기법을 응용한 방법이다.

레코드를 하나의 페이지당 1개의 게시글을 가지도록 분할하고, 그 중 랜덤한 하나의 페이지만 골라오는 것이다.

페이징이 무엇인지 잘 모르겠다면 아래 게시글을 참고하자.

 

 

JPA에서 쓰는 페이징(Paging) 기법이 뭘까?

페이징(Paging) 가끔 궁금한 생각이 들었을 것이다. 커뮤니티의 게시판이나, 구글의 검색 결과는 페이지로 구분이 되는데, 이건 어떤 원리로 동작하는걸까? 라는 궁금증 말이다. 한 걸음 더 나아가

dazbee.tistory.com

 

코드로 구현하면 다음과 같다.

// 조건에 맞는 게시글의 개수를 가져온다.
long qty = postRepository.countByUserNotAndPostIdNotIn(user, readingPostIdList);
// 가져온 개수 중 랜덤한 하나의 인덱스를 뽑는다.
int idx = (int)(Math.random() * qty);

// 페이징하여 하나만 추출해낸다.
Page<Post> postPage = postRepository
	.findAllByUserNotAndPostIdNotIn(
		user,
		readingPostIdList,
		PageRequest.of(idx, 1)
	);

if (postPage.hasContent()) {
	Post post = postPage.getContent().get(0);
}

복잡한 코드도 아니면서, DB에 큰 데이터 덩어리를 배달하도록 요청하는 작업을 시키지 않아도 되도록 잘 만들어진 코드였다. 고맙다. 스택오버플로우!

댓글