Forest Gump?

QueryDsl에서 오라클 nextval 함수 사용하기(feat. chatGPT) 본문

카테고리 없음

QueryDsl에서 오라클 nextval 함수 사용하기(feat. chatGPT)

code1010 2023. 2. 27. 11:29

프로젝트 진행 중에, 오라클 시퀀스를 사용해야 해서 NEXTVAL 함수를 사용하려고 했었다. 

처음에 사용하려고 했던 방법은 다음과 같다 .

 

var a =  entityManager.createNativeQuery("select sequenceName.NEXTVAL from dual").getSingleResult();

 

기본적으로 queryFactory Bean 등록을 할때, entityManager을 파라미터로 등록해줘서 jpql을 이용하는건 아무 문제가 없었다. 사용한 문제의(?) configuration 코드는 다음과 같다.

 

@Configuration
@RequiredArgsConstructor
public class QuerydslConfiguration {

    @PersistenceContext
    private EntityManager entityManager;

    @Bean
    public JPAQueryFactory jpaQueryFactory() {
        return new JPAQueryFactory(this.entityManager);
    }

}

 

 

하지만 queryDsl 을 사용한 다른방법이 있지 않을까해서 찾아보기로 했다. 기존에는 , entity에 SequenceGenerator 을 사용해서 insert 했었지만, value 자체를 뽑아서 사용하는 방법은 아니라 , 구글링을 하다가 chatGPT를 이용해서 답을 찾고싶어져서 사용해보기로 했다. 

 

 

처음 사용했을때 구글링으로 한참 찾았던 정보를 찾아줘서 유레카를 외쳤다. regenration answer버튼을 누를때마다

다른 답변들도 제공해줘서, 5가지 방법을 찾은 후  " 하나는 무조건 되겠지" 라는 생각을 하면서 적용해봤다. 

하지만 쉽게 해결되지는 않았다. queryDsl 자체가 오픈소스기도 하고 엄청 견고한 소스는 아니라 더 그럴 수도 있겠는데, 

chatGPT가 제시 방법은 여기저기 syntax 오류가 나오기도 하고, 가만 보고 있으면  5개의 전부다 뭔가 코드가 한두줄씩

엉성하게 빠져있는 코드라는 생각이 들었다. 실제로 실행 해보기도 해서 해당 오류들도 질의하지만, 뭔가 도르마무 되는 기분이 들었다.  ( 아직 사용을 제대로 못하는 이유가 큰것 같다) 

 

그래서 다시 구글링을 해봤다. 

 

https://github.com/querydsl/querydsl/issues/1515

 

queryDsl 레포의 issue tab에서 방법을 찾았다. 

 

Expression<Long> nextval = SQLExpressions.nextval(Long.class,"CHK.SEQ_TB_STATUS_CHANGE");
return queryFactory.select(nextval).fetchFirst();

바로 nextVal함수를 사용하는 이런 간단한 방법을 chatGPT는 안알려줬을까.. 하며 방법을 적용해봤다. 

 

 

해당 구문의 오류
queryFactory를 사용하지 않고도 찍어봤다.

방법을 사용했지만, 오류가 여전히 나왔다. 

 

2023-02-23 09:31:40.008 ERROR 25856 --- [p-nio-80-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: SQL Expressions like NEXTVAL are not supported in JPQL - the query language for JPA. SQLExpressions.* can only be used in JPQL queries when these functions are registered as custom function in your ORM.
	To fix this issue, you have three options:
	1) If you do want to use advanced, dialect specific, SQL functions within JPQL, make sure to make these functions available to your ORM through custom functions and register these with your JPATemplates instance.
	2) Use JPASQLQuery instead. This allows you to generate a pure SQL query based on your JPA metamodel.
	3) Consider using the Blaze-Persistence QueryDSL integration. Blaze-Persistence is an extension on top of JPA that makes various SQL specific functions like window functions available to JPQL.; nested exception is java.lang.IllegalArgumentException: SQL Expressions like NEXTVAL are not supported in JPQL - the query language for JPA. SQLExpressions.* can only be used in JPQL queries when these functions are registered as custom function in your ORM.
	To fix this issue, you have three options:
	1) If you do want to use advanced, dialect specific, SQL functions within JPQL, make sure to make these functions available to your ORM through custom functions and register these with your JPATemplates instance.
	2) Use JPASQLQuery instead. This allows you to generate a pure SQL query based on your JPA metamodel.
	3) Consider using the Blaze-Persistence QueryDSL integration. Blaze-Persistence is an extension on top of JPA that makes various SQL specific functions like window functions available to JPQL.] with root cause

java.lang.IllegalArgumentException: No pattern found for NEXTVAL. Make sure to register any custom functions with class com.querydsl.jpa.Hibernate5Templates.

또 한번 에러 중에서 더 희망적인 사실은,  다른 오류가 친절한 이유까지 설명을 해주면서 나오니 단순히 안된다는 chatGPT 구문보다 도움이 됐다. 여기서 이리저리 구글링 더 하면서 삽질을 몇시간 가량 했다. 

 

결론적으로 방법을 찾았다! 

 

해당 오류구문 2번을 보면 "Use JPASQLQuery Instead" 라는 말을 넘긴게 삽질의 이유였다. 

 지금까지 사용한 queryDsl은 앞에서 configuration 에 문제의 코드라고 했던 부분으로 bean 에 등록을 해서 사용을 했다. 

gitHub issue문서에서도 queryFactory로 사용을 하고 select 하는 구문도 내가 사용하는 방법과 같아서 전혀 이상함을 못알아챘었는데, queryDsl 를 jpa 객체로 사용하는 방법이 아닌, sql 구문으로 사용하는 방법이 있다는 걸 다른 동료분께서 

말씀해주셨다. 

 

바로 chatGPT로 해당 의존성을 물어보고 configuration 에 적용을 했다.( 사용할 구문의 groovy dependency등을 질의할떄는 구글링보다 훨씬 좋은것 같다. )

해당 의존성은 다음과 같다. 

 

 

@Configuration
@RequiredArgsConstructor
public class QuerydslConfiguration {
    @PersistenceContext
    private EntityManager entityManager;

    private final DataSource dataSource;

    @Bean
    public JPAQueryFactory jpaQueryFactory() {
        return new JPAQueryFactory(this.entityManager);
    }

    @Bean
    public SQLQueryFactory sqlQueryFactory() {

        OracleTemplates templates1 = new OracleTemplates();
        com.querydsl.sql.Configuration configuration = new com.querydsl.sql.Configuration(templates1);

        return new SQLQueryFactory(configuration,dataSource);
    }
}

 

Configuration 에 bean 등록을 하고 queryDsl github issue에 있는코드를 사용해봤다. 

 

Expression<Long> nextval = SQLExpressions.nextval(Long.class,"CHK.SEQ_TB_STATUS_CHANGE");
return queryFactory.select(nextval).fetchFirst();

아깐 에러를 뱉던 코드가 정상적으로 실행이 됐다 ! 

bean 등록 이름이 queryFactory로 되있어서 같은 라이브러리를 이용한 줄 알고 해당 방법에서만 많이 헤맸던것 같다.

 

chatGPT한테도 질의를 잘하는 방법을 연구해봐야겠다.