[MySQL] Spring Boot 에서 MySql의 랜덤 함수 사용하기 (QueryDSL)

2024. 1. 30. 11:42기술 창고/DataBase

728x90
SMALL

Spring Boot 를 통해 프로젝트를 만들고 DB는 MySQL을 사용할 때 일반적으로 JPA나 JPQL, 혹은 QueryDSL을 주로 사용할 것 입니다.

일반적인 기본 연산들이나 조회 연산들은 수행되지만 MySQL 워크 벤치에서는 수행되는 랜덤 함수는 JPQL을 사용할 때는 지원하지만 일반적인 JPA나 QueryDSL을 사용할 때에는 지원하지 않습니다.

이를 JPA나 QueryDSL을 사용하고 있는 환경에서 사용하기 위해서는 별도의 Template 처리를 통해 랜덤 함수를 사용하겠다는 설정을 해주어야 합니다.

 

오늘은 QueryDSL 환경에서 랜덤 함수를 사용할 수 있는 방법에 대해 간단하게 정리해보겠습니다.

 

 

(1) 템플릿 생성 및 설정

import com.querydsl.core.types.Ops;
import com.querydsl.jpa.JPQLTemplates;

public class MySqlJpaTemplates extends JPQLTemplates {

    public static final MySqlJpaTemplates DEFAULT = new MySqlJpaTemplates();

    public MySqlJpaTemplates() {
        this(DEFAULT_ESCAPE);
        add(Ops.MathOps.RANDOM, "rand()");
        add(Ops.MathOps.RANDOM2, "rand({0})");
    }

    public MySqlJpaTemplates(char escape) {
        super(escape);
    }
}

랜덤 함수를 사용하기 위한 템플릿을 만들어줍니다.

 

- 랜덤 함수를 지원하는 JPQLTemplates을 extends 받습니다.

JPQLTemplates는 연산자 패턴을 통해 쿼리 관련 함수를 사용할 수 있도록 제공받을 수 있습니다.

MySqlJpaTemplates의 생성자에 지원하는 add 함수를 사용함으로서 랜덤 함수를 지원받았습니다.

Operator의 RANDOM 기능을 넣고 랜덤 기능을 뜻하는 rand() 함수를 넣어서 추가합니다.

 

기타 add 명령어

이외에도 다른 연산 기능을 넣고 싶으면 add 함수를 통해 적용할 수 있습니다.

 

 

(2) JPAQuery 객체를 통해 랜덤 함수 사용

import com.querydsl.jpa.impl.JPAQuery;

@Slf4j
@Component
@RequiredArgsConstructor
public class AlbumTrackQueryData {
    private final EntityManager entityManager;

    public List<Album> getRandomAlbums(){
        // 랜덤 추출을 위한 MySqlJpaTemplates 호출
        JPAQuery<Album> query = new JPAQuery<>(entityManager, MySqlJpaTemplates.DEFAULT);

        // MySqlJpaTemplates을 통해 앨범 상세 페이지에 같이 보여지게 될 유사한 장르를 가진 랜덤 앨범 5개를 추출
        List<Album> random5SimilarAlbums = query
                .from(album)
                .where(album.genre.eq(detailAlbum.getGenre()).and(album.albumId.ne(detailAlbum.getAlbumId())))
                .orderBy(NumberExpression.random().asc()) // 랜덤 함수 사용
                .limit(5)
                .fetch();
                
         return random5SimilarAlbums;
    }
}

 

 

- JPAQuery를 호출하여 엔티티를 가지고 있는 EntityManager와 위에서 랜덤 함수 사용 설정을 한 MySqlJpaTemplates.DEFAULT를 적용합니다.

List 를 사용하는 것처럼 <> 괄호 안에는 적용할 엔티티를 넣어줍니다.

 

- 랜덤 쿼리를 사용합니다.

QueryDSL 쿼리 명령어 내에서 orderBy 문에 랜덤 명령어를 사용할 수 있습니다.

NumberExpression.random() 명령어를 통해 랜덤 기능을 활성화시킬 수 있습니다.

이 때 orderBy를 사용하였으므로, 반드시 asc나 desc 정렬 명령어도 같이 사용해주어야 합니다.

 

위의 제가 구성한 쿼리를 보면,

 

query
.from(album)  ->  Album 테이블에서
.where(album.genre.eq(detailAlbum.getGenre())  ->  앨범 장르가 detailAlbum 의 앨범 장르와 같고

           .and(album.albumId.ne(detailAlbum.getAlbumId())))  ->  앨범의 id가 detailAlbum 의 id와 다른 앨범들을 
.orderBy(NumberExpression.random().asc())  ->  랜덤으로 (오름차순)
.limit(5)  ->  5개 추출
.fetch();

 

하겠다는 의미입니다.

 

 

이제 결과를 확인해보겠습니다.

 

[첫 번째 실행 결과]

"similarAlbumList": [
            {
                "albumId": 2,
                "albumTitle": "다중 두 번째 앨범",
                "artist": "KING_JSH",
                "albumImg": "http://116.125.141.139:8090/image/0b6156cf-3360-4f45-a00a-18a59e9856dd.jpg"
            },
            {
                "albumId": 13,
                "albumTitle": "테스트 앨범3",
                "artist": "KING_JSH",
                "albumImg": "http://116.125.141.139:8090/image/f35d34ce-b7f9-4e11-b59f-a93aba99fe51.jpg"
            },
            {
                "albumId": 22,
                "albumTitle": "테스트 앨범3",
                "artist": "KING_JSH",
                "albumImg": "http://116.125.141.139:8090/image/89440fb3-fa34-4c42-85f6-f30dca2a4af6.jpg"
            },
            {
                "albumId": 27,
                "albumTitle": "테스트 앨범3",
                "artist": "KING_JSH",
                "albumImg": "http://116.125.141.139:8090/image/a480a31e-46eb-480d-a2c5-8b519a9876b8.jpg"
            },
            {
                "albumId": 3,
                "albumTitle": "단일 세 번째 앨범",
                "artist": "KING_JSH",
                "albumImg": "http://116.125.141.139:8090/image/80a88bc8-baf2-4b45-b3ea-fc66938709e0.jpg"
            }
        ]

 

 

[두 번째 실행 결과]

"similarAlbumList": [
            {
                "albumId": 2,
                "albumTitle": "다중 두 번째 앨범",
                "artist": "KING_JSH",
                "albumImg": "http://116.125.141.139:8090/image/0b6156cf-3360-4f45-a00a-18a59e9856dd.jpg"
            },
            {
                "albumId": 23,
                "albumTitle": "테스트 앨범3",
                "artist": "KING_JSH",
                "albumImg": "http://116.125.141.139:8090/image/e622d219-d2bf-4c78-9158-abfb90dbfa43.jpg"
            },
            {
                "albumId": 26,
                "albumTitle": "테스트 앨범3",
                "artist": "KING_JSH",
                "albumImg": "http://116.125.141.139:8090/image/0bbaa86c-dd45-4a46-bc7e-34fada45d262.jpg"
            },
            {
                "albumId": 6,
                "albumTitle": "테스트 앨범2",
                "artist": "KING_JSH",
                "albumImg": "http://116.125.141.139:8090/image/52c68e32-8bac-4ff4-baec-78118079fcdc.jpg"
            },
            {
                "albumId": 21,
                "albumTitle": "테스트 앨범3",
                "artist": "KING_JSH",
                "albumImg": "http://116.125.141.139:8090/image/f2d4620c-7327-46d9-a592-9211177136d9.jpg"
            }
        ]

위에서 나온 결과들에서 볼 수 있듯이, 실행할 때마다 랜덤으로 결과값들이 도출되는 것을 확인할 수 있습니다.

 

728x90
반응형
LIST