본문 바로가기

Spring

Spring JPA @Query 사용하기 JPQL

728x90

Spring legacy 프로젝트를 개발하면서 JPA를 처음 사용해봤다.

Mybatis에 익숙해진 나는 쿼리를 직접 쓰고 db에 만들어놓은 프로시저나 함수를 이용하는 쿼리를 작성하는게 익숙했는데 jpa는 인터페이스에서 제공하는 메서드만 사용하기 때문에 사용할 방법이 없었다.

하지만 찾아보니 JPA에서도 @Query 어노테이션을 사용해 직접 쿼리를 작성해 새로운 커스텀 메서드를 생성하는게 가능했다. => 이를 JPQL이라고 한다.

 

추가로 콘솔에 쿼리를 로깅하기 위한 설정을 했다.

 

Repository에서 @Query 사용

 

package com.poozim.jobcall.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;

import com.poozim.jobcall.model.Work;

public interface WorkRepository extends JpaRepository<Work, Integer>{
	@Modifying
	@Transactional
	@Query(value = "INSERT INTO Work (member_seq, title, code, email, useyn, register, regdate) VALUES (:#{#work.member_seq}, :#{#work.title}, getWorkCode(:#{#work.title}), :#{#work.email}, 'Y', :#{#work.register}, NOW())", 
			nativeQuery = true)
	public int saveJpql(@Param("work") Work work);
	
}

코드에는 jpa에서 제공하는 save에 한계를 느끼고 새로 생성한 메서드 saveJpql을만들었다.

내 경우 Insert 하는 쿼리를 작성해 보았다.

 

jpa에서 제공하는 save를 오버라이딩이나 오버로딩해서 사용하는것도 가능하지만 오버라이딩은 구현이 힘들고 오버로딩이나 새로운 메서드를 만드나 같은 맥락이니 새로 만들어보았다.

 

파라미터

@Query를 사용할때 파라미터를 입력해주어야 하는데, Mybatis의 경우 디테일하게 설정하지 않아도 #{필드명} 만으로도 값 설정이 가능했다, 하지만 @Query를 사용해 직접 설정하는경우, 즉 JPQL을 하는경우에 파라미터는 :#{#파라미터객체.필드명}의 형태로 설정이 가능하다. 

 

매개변수를 @Pram("파라미터명") ~~~ xxx 의 경우로 설정했다면 :#{#파라미터명}으로 사용이 가능한것도 같은 원리다.

 

 

@Transactional

@Transactional의 어노테이션이 없다면, TransactionRequiredException: Executing an update/delete query의 에러를 뱉어버린다. 에러내용으로 봐서 select쿼리가 아니라면 필수로 써야하는 어노테이션이다.

 

@Modifying

@Modifying 어노테이션 역시 select쿼리가 아니라면 반드시 써줘야하는 어노테이션이다. 안쓰면 마찬가지로 Can not issue data manipulation statements with executeQuery() 같은 에러를 뱉게된다. @Modifying을 사용하면 리턴형태는 무조건 int형이 되어야한다. 안그러면 또 에러를뱉는다.

 


Console Logging (log4j)

스프링 부트의 경우 jpa를 사용하기 아주 좋게 application.properties에 값만 설정해주면 자동으로 쉽게 된다. 스프링 레거시가 불편하다는건 아니지만 부트에 비해 상대적으로 따로 설정해줄 필요가 있다. 

 

콘솔에 로깅을 위해 설정해야할 2가지 파일이 있다.

  • META-INF의 Persistence.xml
  • log4j.xml

 

Persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/persistence" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence 
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
	<persistence-unit name="jobcall">
		<class>com.poozim.jobcall.model.Work</class>
		<class>com.poozim.jobcall.model.WorkBoard</class>
		<class>com.poozim.jobcall.model.WorkBoardFile</class>
		<class>com.poozim.jobcall.model.WorkGroup</class>
		<class>com.poozim.jobcall.model.Member</class>
		<class>com.poozim.jobcall.model.Comment</class>
		<class>com.poozim.jobcall.model.CommentFile</class>
		<class>com.poozim.jobcall.model.FavoritLog</class>
		<class>com.poozim.jobcall.model.StatusLog</class>
		
		<properties>
			<!-- <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/> -->
			
			<property name="hibernate.show_sql" value="true"/>
			<property name="hibernate.format_sql" value="true"/>
			<property name="hibernate.use_sql_comments" value="true"/>
			<property name="hibernate.c3p0.min_size" value="5"/>
			<property name="hibernate.c3p0.max_size" value="20"/>
			<property name="hibernate.c3p0.timeout" value="500"/>
			<property name="hibernate.c3p0.idle_test_period" value="2000"/>
		</properties>
	</persistence-unit>
</persistence>

이중에 쿼리와 관련된 설정은 3가지다.

<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.use_sql_comments" value="true"/>

 

hibernate.show_sql : 쿼리문을 콘솔에 보여준다. 근데 악간 뒤틀린 형태로 다르게 찍힌다.

hibernate.format_sql : 뒤틀린 쿼리문을 보기 편한? 형태로 보여준다.

hibernate.use_sql_comments : 쿼리문에 주석으로 설명을 추가해준다. (개인적으로 필요 없는듯 하다)

 

 

여기까지 하면 쿼리문은 보이지만 파라미터 값의 경우 ?로 보일것이다. 그래서 log4j.xml에 추가 설정이 필요하다.

log4j.xml

 

<logger name="org.hibernate.type.descriptor.sql.BasicBinder">
		<level value="TRACE" />
	</logger>
	
	<logger name="org.hibernate.SQL">
		<level value="debug" />
	</logger>

결과는 각자 확인하길

728x90