하이버네이트 6 사용자 정의 함수 등록

jhkim31·2024년 7월 10일
0

JSHOP 프로젝트

목록 보기
8/8

하이버네이트 6 버전을 사용하며 JPA 표준으로 지원하지 않는 JSON 관련 함수를 등록해 사용하는 방법에 대해 정리한 글이다.

하이버네이트

하이버네이트는 JPA의 구현체중 하나로, 가장 많이 사용되는 JPA 구현체다.

하이버네이트는 기본적으로 데이터베이스 방언 기능을 제공한다. 이 기능은 개발자가 코드를 작성하면 데이터베이스에 맞는 쿼리로 알아서 변환해주는 기능이다.

방언은 일반적인 SQL을 생성하는것이 목적이기 때문에 특정 데이터베이스에서만 제공하는 함수같은 기능은 제공하지 못한다.

MySQL JSON_CONTAINS

MySQL 은 5.7 버전부터 JSON 타입을 지원한다. 어떻게 보면 역정규화된 필드이긴 하지만 잘 사용한다면 편의와 성능등 여러 이점이 있을 수 있다.

나의 경우 상품의 속성을 정의하기 위해 JSON 타입을 사용했다.

{
  "color" : "red",
  "size" : 100
}

위와같이 상품의 속성을 정의할때 상품마다 어떤 키-값이 올지 모르고, 몇개가 올지 모르기 때문에 JSON을 사용하기로 했다.

MySQL에서는 JSON으로 조건을 걸 수 있는 JSON_CONTAINS 라는 함수를 제공한다.

select * from product where json_contains(attribute, '{"color" : "red"}')

위와같이 사용한다면, 특정 상품에서 속성중에 "color" 키의 값이 "red" 값인 모든 상품이 조회된다.
(일치가 아니라 포함임)

하지만 데이터베이스의 추상화가 목적인 JPA에서는 MySQL의 특화된 쿼리인 JSON_CONTAINS 를 지원하지 않는다.

그래서 JSON_CONTAINS 를 사용하기 위해선 몇가지 작업을 해줘야 한다.

사용자 정의 함수 추가

JPA의 구현체인 Hibernate 에 사용자 정의 함수를 추가해 SQL로 번역할 수 있도록 해줘야 한다.

나의 경우 JSON_CONTAINS 함수를 JPA에서 사용할 수 있도록 추가할 거다.

FunctionContributor 인터페이스 구현

FunctionContributor 인터페이스를 구현한다.

public class CustomFunctionContributor implements FunctionContributor {

    @Override
    public void contributeFunctions(FunctionContributions functionContributions) {
        functionContributions
            .getFunctionRegistry()
            .registerPattern("json_contains", "json_contains(?1, ?2)",
                functionContributions.getTypeConfiguration().getBasicTypeRegistry().resolve(BOOLEAN));
    }
}

json_contains 라고 JPQL에서 사용하면, json_contains(?1, ?2) 로 번역해 사용하라고 등록해준다.
그리고 JSON_CONTAINS 의 리턴 타입은 boolean 이니 타입을 잘 맞춰 등록해준다.

META-INF 등록

구현한 FunctionContributor 를 META-INF에 등록해준다.

src/main/resources/META-INF/services/org.hibernate.boot.model.FunctionContributor 파일에 아래와 같이 작성한 커스텀 함수를 추가한다.

jshop.global.hibernate.CustomFunctionContributor

테스트

추가한 json_contains 가 잘 동작하는지 확인해본다.

em.createQuery("select pd from ProductDetail pd where json_contains(pd.attribute, '{\"attr1\" : \"1\"}')",
            ProductDetail.class);

잘 번역되어 나가는것을 확인할 수 있다.

ref

https://discourse.hibernate.org/t/migration-of-dialect-to-hibernate-6/6956

profile
김재현입니다.

0개의 댓글