본문 바로가기
프로그램/자바

3장. Querydsl 입문

by cbwstar 2021. 5. 24.
728x90
반응형

Querydsl 입문, 장점, Querydsl의 종류, 구문, SQLQuery, SQLQueryFactory, JPAQuery, JPAQueryFactory, Q 타입클래스 생성

 

3. Querydsl 입문

Querydsl은 미리 작성한 쿼리타입 클래스를 사용해서 쿼리를 메소드 기반으로 작성할 수 있도록 도와주는 프레임워크입니다. 문자열로 작성하거나 XML 파일에 쿼리를 작성하는 대신 Querydsl이 제공하는 메소드를 사용해서 쿼리를 작성합니다.

 

 

3.1. 장점

문자열로 쿼리를 작성하는 대신 Querydsl을 사용하여 자바코드로 쿼리를 작성하게 되면 얻을 수 있는 장점은 다음과 같습니다.

 

n     IDE의 코드 자동완성 기능을 사용할 수 있어서 보다 빠른 개발이 가능하다.

n     문법적으로 잘못된 쿼리를 거의 허용하지 않아 안전하다.

n     도메인 타입과 프로퍼티를 편리하게 참조할 수 있다.

n     도메인 타입의 리팩토링 작업이 수월하다.

 

타입에 안전하게 쿼리를 작성해서 얻는 이득이 무엇일지 잠시 생각해 봅니다. 메소드 기반으로 쿼리를 작성하기 때문에 도메인 관련 변경 작업 시 변경이 자동적으로 쿼리에 반영되므로 변화가 있을 때 좀 더 유연하게 적용할 수 있습니다. 또한 쿼리 작성 과정에서 IDE 툴이 제공하는 코드 자동완성 기능을 사용함으로써 쿼리를 더 빠르게 만들 수 있다는 점도 도움이 되는 부분입니다.

 

Querydsl JPQL Criteria 기술을 모두 대체할 수 있습니다.
Querydsl
 Criteria 기술에서 제공했던 쿼리를 조건에 따라 동적으로 작성하는 기능과 JPQL 작성을 타입에 안전한 방법으로 작성하는 방법을 모두 제공합니다.

 

 

 

3.2. Querydsl의 종류

Querydsl은 엔티티로 설정된 모델 클래스와 동일한 패키지에 "Q" 모델이라는 쿼리타입 클래스를 미리 생성해 놓고 메타데이터로 사용하여 쿼리를 메소드 기반으로 작성합니다. Querydsl을 사용하면 보다 쉽고 직관적으로 처리할 수 있습니다.

 

3.2.1. Querydsl 구분

  Thread Safe


as Bean(Singleton)

Use EntityManager


(First Caching)

Use Entity Class

JPAQuery

new

v

v

JPAQueryFactory

v

v

v

JPASQLQuery

new

v (No First Caching)

Table

SQLQuery

new

DataSource

Table

SQLQueryFactory

v

DataSource

Table

 

n     쿼리문을 작성하기 위해서 모두 Q 타입 클래스를 사용합니다.

n     JPAQuery, JPAQueryFactory 클래스를 사용하면 EntityManager를 통해서 질의가 처리되고 이 때 사용하는 쿼리문은 JPQL 입니다.

n     SQLQuery, SQLQueryFactory 클래스를 사용하면 JDBC 기술을 사용하여 질의가 처리되고 이 때 사용하는 쿼리문은 SQL입니다.

n     JPASQLQuery 클래스를 사용하면 EntityManager를 통해서 질의가 처리되고 이 때 사용하는 쿼리문은 SQL입니다. 추가적으로 EntityManager를 이용하고 싶을 때 사용합니다.

 

3.2.2. 엔티티 클래스를 만들어서 사용

"Q" 모델은 클래스 내 자체적으로 이미 인스턴스를 static 변수로 가지고 있기 때문에 예를 들어 "QEmp.emp" 처럼 간단하게 사용할 수 있습니다.

 

1. JPAQuery

QEmp emp = QEmp.emp;

JPAQuery query = new JPAQuery(em);     

query.select(emp).from(emp).where(emp.ename.eq("SMITH"));     

List<Emp> result = query.fetch();

 

JPAQuery 생성자에 EntityManager 객체를 전달합니다.

select 메소드는 얻고자 하는 칼럼들을 지정하는 Projection설정용입니다.

from 메소드는 쿼리대상을 지정합니다.

where 메소드는 쿼리 조건을 적용하는 필터입니다.

fetch 메소드로 복수의 로우 데이터를 얻을 수 있습니다.

 

대부분의 데이터베이스는 저장하는 정보를 필터링할 때 대소문자를 구분하기 때문에 "SMITH" 문자열을 소문자로 사용하면 해당 데이터가 없다고 할 것이니 주의가 필요합니다.

 

2. JPAQueryFactory

JPAQueryFactory  queryFactory = new JPAQueryFactory(em);

List<Emp> emps = queryFactory.selectFrom(emp).where(emp.ename.eq("SMITH")).fetch();

 

JPAQueryFactory JPAQuery를 만들어서 사용하는 방식입니다. JPAQueryFactory를 빈 컨테이너에 등록해 놓고 DI 받아 사용하면 편리합니다. JPAQueryFactory JPQLQueryFactory 인터페이스를 구현했으며 JPAQuery 인스턴스를 포함하여 다양한 방법으로 쿼리 할 수 있습니다. 생성할 때 EntityManager만 인자로 넣어 생성할 수도 있고 JPQLTemplate도 같이 인자로 줘서 생성 할 수 있습니다. 다이나믹하게 데이터베이스가 바뀌는 경우는 거의 없기 때문에 보통 JPQLTemplate은 생략하고 사용합니다.

 

selectFrom(emp) 메소드는 select(emp).from(emp) 선언의 축약형태입니다.

eq 메소드는 "=" 연산자를 대체하는 메소드입니다.

 

3.2.3. 엔티티 클래스를 만들지 않고 사용

 

1. JPASQLQuery

엔티티 클래스를 만들지 않고 사용할 수 있습니다. 엔티티 클래스를 작성한 후 이를 바탕으로 테이블을 구성하여 진행하는 개발방식 대신 이미 테이블이 존재하는 경우 이를 바탕으로 쿼리타입을 생성하여 질의할 때 이용하는 방식입니다.

 

이는 엔티티매니저의 createNativeQuery 메소드를 사용하는 것과 결과가 같습니다. 하지만 둘 사이에는 큰 차이가 존재합니다.

 

JPASQLQuery 클래스를 사용하거나 em.createNativeQuery 메소드를 사용하거나 둘 다 개발자가 지정해서 알려 준 쿼리를 사용합니다. em.createNativeQuery에서 파라미터로 넘겨주는 모델클래스는 엔티티이므로 여러 엔티티 클래스의 연관관계에 따른 EAGER 로딩정책을 지키기 위해서 추가적으로 쿼리가 더 수행될 수 있습니다.

하지만 new JPASQLQuery<Void>(em, templates) 코드에서 보는 것처럼 엔티티매니저를 사용한다고 하더라도 엔티티 클래스를 알려 준 것은 아니므로 연관관계에 따른 추가적인 쿼리가 수행되지 않는다는 차이점이 존재합니다. 더불어 엔티티 클래스를 이용한 것이 아니므로 1차 캐싱기능을 이용하지 못합니다. 질의를 하면 엔티티매니저가 매번 데이터베이스에 질의하여 데이터를 얻어다 줄 것입니다.

 

JPAQuery 객체로는 인라인뷰 쿼리를 작성하지 못합니다. 따라서 인라인뷰를 사용하고자 하는 경우에는 대신 JPASQLQuery를 사용해야 합니다. 인라인뷰를 사용하지 못하는 것은 Querydsl의 한계가 아니라 JPA의 기술적인 한계입니다.

 

JPASQLQuery를 사용하기 위해서 우선 테이블을 바탕으로 리버스 엔지니어링을 진행하여 쿼리타입 클래스를 생성해야 합니다. 이 때 필요하다면 모델 클래스를 같이 생성할 수 있습니다. 메이븐 설정에 querydsl-maven-plugin을 추가하여 Q 타입 클래스를 생성한 다음 이용합니다.

 

SQLTemplates templates = new DerbyTemplates();

QEmp emp = new QEmp("emp");

JPASQLQuery<?> query = new JPASQLQuery<Void>(em, templates);

List<Tuple> rows = query.select(emp.empno, emp.ename).from(emp)

        .where(emp.ename.eq("SMITH").fetch();

 

SQLTemplates의 구현체는 데이터베이스에 따라서 선택해서 사용합니다. 선택된 구현체를 파라미터로 전달하고 사용해야 하는 Dialect를 판단하는 용도로 사용됩니다.

2. SQLQuery

SQLQuery를 직접 사용하는 방법보다는 SQLQueryFactory를 통해서 사용하는 방법을 권장합니다. 따라서 SQLQueryFactory를 사용하는 방법을 바로 살펴 보겠습니다.

 

3. SQLQueryFactory

SQLTemplates templates = new MySQLTemplates();

Configuration configuration = new Configuration(templates);

SQLQueryFactory queryFactory = new SQLQueryFactory(configuration, dataSource);

QEmp emp = new QEmp("emp");

List<Emp> result  = queryFactory.selectFrom(emp).where(emp.ename.eq("SMITH")).fetch();          

 

SQLQueryFactory 생성자에 설정정보인 Configuration 과 데이터베이스 연결정보인 DataSource를 주고 있습니다. 따라서 엔티티매니저를 거쳐서 사용하는 것이 아닌 개발자가 직접 데이터베이스가 이해하는 SQL을 작성한 다음 JDBC 기술을 사용하여 처리하는 방식이라는 것을 알 수 있습니다.

 

다음은 이해를 돕기위한 com.querydsl.sql.AbstractSQLQuery.fetch 메소드 소스의 일부분 입니다.

//… 생략
final PreparedStatement stmt = getPreparedStatement(queryString);

try {

        setParameters(stmt, constants,

                 serializer.getConstantPaths(), queryMixin.getMetadata().getParams());

        context.addPreparedStatement(stmt);

        listeners.prepared(context);

 

        listeners.preExecute(context);

        final ResultSet rs = stmt.executeQuery();

        listeners.executed(context);

        //... 생략

} finally {

        stmt.close();

}

//... 생략

 

SQLQueryFactory를 이용하는 경우 내부적으로 Querydsl JDBC기술을 사용한다는 것을 알 수 있습니다.

 

3.3. JPAQuery, JPAQueryFactory

이제부터 Querydsl의 사용법을 종류별로 자세히 살펴보겠습니다.

 

 

3.3.1. 프로젝트 생성

앞서 만든 프로젝트 chapter2-3을 소스 전체를 복사하여 chapter3-3 이름으로 프로젝트를 만듭니다.

 

3.3.2. 프로젝트 환경설정

로깅 디펜던시와 JPAQuery 사용을 위한 Querydsl 디펜던시를 확인합니다.

pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"

        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

        <modelVersion>4.0.0</modelVersion>

 

        <groupId>com.example</groupId>

        <artifactId>boot</artifactId>

        <version>0.0.1-SNAPSHOT</version>

        <packaging>jar</packaging>

 

        <parent>

                 <groupId>org.springframework.boot</groupId>

                 <artifactId>spring-boot-starter-parent</artifactId>

                 <version>1.4.1.RELEASE</version>

                 <relativePath /> <!-- lookup parent from repository -->

        </parent>

 

        <properties>

                 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

                <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

                 <java.version>1.8</java.version>

        </properties>

 

        <dependencies>

                 <dependency>

                         <groupId>org.springframework.boot</groupId>

                         <artifactId>spring-boot-starter-data-jpa</artifactId>

                 </dependency>

                 <dependency>

                         <groupId>org.projectlombok</groupId>

                         <artifactId>lombok</artifactId>

                 </dependency>

                 <dependency>

                         <groupId>org.springframework.boot</groupId>

                         <artifactId>spring-boot-starter-web</artifactId>

                 </dependency>

 

                 <dependency>

                         <groupId>mysql</groupId>

                         <artifactId>mysql-connector-java</artifactId>

                         <scope>runtime</scope>

                 </dependency>

                 <dependency>

                         <groupId>org.springframework.boot</groupId>

                         <artifactId>spring-boot-starter-test</artifactId>

                         <scope>test</scope>

                 </dependency>

                

                 <dependency>

                         <groupId>org.bgee.log4jdbc-log4j2</groupId>

                         <artifactId>log4jdbc-log4j2-jdbc4.1</artifactId>

                         <version>1.16</version>

                 </dependency>

                 <!-- Spring Boot 프로젝트를 만들 경우 버전설정은 생략 가능 -->

                 <dependency>

                         <groupId>com.querydsl</groupId>

                         <artifactId>querydsl-apt</artifactId>

                         <scope>provided</scope>

                 </dependency>

                 <dependency>

                         <groupId>com.querydsl</groupId>

                         <artifactId>querydsl-jpa</artifactId>

                </dependency>

                 <!-- Spring Boot 프로젝트를 만들 경우 slf4j-log4j12 디펜던시 선언은 생략 가능 -->

                 <!--

                 <dependency>

                         <groupId>org.slf4j</groupId>

                         <artifactId>slf4j-log4j12</artifactId>

                         <version>1.6.1</version>

                 </dependency>

                  -->

        </dependencies>

 

        <build>

                <plugins>

                         <plugin>

                                  <groupId>org.springframework.boot</groupId>

                                  <artifactId>spring-boot-maven-plugin</artifactId>

                         </plugin>

                         <!-- Q 타입 클래스 생성을 위한 플러그인 설정 -->

                         <plugin>

                                  <groupId>com.mysema.maven</groupId>

                                  <artifactId>apt-maven-plugin</artifactId>

                                  <version>1.1.3</version>

                                  <executions>

                                          <execution>

                                                  <goals>

                                                           <goal>process</goal>

                                                  </goals>

                                                  <configuration>

                                                           <outputDirectory>

                                                                target/generated-sources/java

                                                        </outputDirectory>

                                                           <processor>

                                                                com.querydsl.apt.jpa.JPAAnnotationProcessor

                                                        </processor>

                                                  </configuration>

                                          </execution>

                                  </executions>

                         </plugin>

                 </plugins>

        </build>

 

</project>

 

 

 

3.3.3. Q 타입클래스 생성

프로젝트 선택 > 마우스 오른쪽 클릭 > Run AS >

Maven generate-sources 또는 Maven install 선택

 

생성 확인

프로젝트 선택 > 새로고침 > target/generated-sources/java 폴더 및 Q 타입 클래스 생성 확인

 

소스 폴더로 등록

target/generated-sources/java 폴더 선택 > 마우스 오른쪽 클릭 > Build Path > Use as Source Folder


 

 

작업 결과


 

 

3.3.4. Persistence Layer

다음 작업으로 클래스를 추가로 작성합니다. 클래스의 위치는 소스의 package 정보를 참고하세요.

EmpDao.java

package com.example.employee.repository;

 

import java.util.List;

import com.example.employee.model.Emp;

 

public interface EmpDao {

        public List<Emp> getByEname1(String ename);

        public List<Emp> getByEname2(String ename);

}

 

EmpDaoImpl.java

package com.example.employee.repository;

 

import java.util.List;

import javax.persistence.EntityManager;

import javax.persistence.PersistenceContext;

import org.springframework.stereotype.Repository;

import com.example.employee.model.Emp;

import com.example.employee.model.QEmp;

import com.querydsl.jpa.impl.JPAQuery;

import com.querydsl.jpa.impl.JPAQueryFactory;

 

@Repository

public class EmpDaoImpl implements EmpDao {

        @PersistenceContext

        private EntityManager em;

       

        @Override

        public List<Emp> getByEname1(String ename) {

                 QEmp emp = QEmp.emp;

                 JPAQuery<Emp> query = new JPAQuery<Emp>(em);
                // select * from emp where ename='SMITH'

                 query.select(emp).from(emp).where(emp.ename.eq("SMITH"));     

 

                 return query.fetch();

        }

       

        @Override

        public List<Emp> getByEname2(String ename) {

                 QEmp emp = QEmp.emp;

                 JPAQueryFactory  queryFactory = new JPAQueryFactory(em);

                // select * from emp where ename='SMITH'

                 return queryFactory.selectFrom(emp).where(emp.ename.eq("SMITH")).fetch();

        }

}

 

 

 

3.3.5. JUnit 테스트 클래스 작성

EmpDaoImpl.java 파일 선택 > 마우스 오른쪽 클릭 >

New > JUnit Test Case 선택

 


 

 

EmpDaoImplTest.java

package com.example.employee.repository;

 

import static org.hamcrest.CoreMatchers.*;

import static org.junit.Assert.assertThat;

import java.util.List;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.test.context.SpringBootTest;

import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;

import org.springframework.test.context.junit4.SpringRunner;

import com.example.employee.model.Emp;

 

@RunWith(SpringRunner.class)

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)

public class EmpDaoImplTest {

        @Autowired

        private EmpDaoImpl empDao;

        private final String TEST_ENAME = "SMITH";

       

        @Test

        public void testGetByEname1() {

                 List<Emp> result = empDao.getByEname1(TEST_ENAME);

                 for (Emp emp : result) {

                         System.out.println(emp);

                 }

                

                 assertThat(result.size(), is(1));

                 assertThat(result.get(0).getEname(), is(TEST_ENAME));

        }

 

        @Test

        public void testGetByEname2() {

                 List<Emp> result = empDao.getByEname2(TEST_ENAME);

                 for (Emp emp : result) {

                         System.out.println(emp);

                 }

                

                 assertThat(result.size(), is(1));

                 assertThat(result.get(0).getEname(), is(TEST_ENAME));

        }

 

}

 

 

3.3.6. 테스트

EmpDaoImplTest > 마우스 오른쪽 클릭 > Run As > JUnit Test 선택

 

두 개의 메소드는 JPAQuery를 사용하거나 JPAQueryFactory를 사용하는 정도에 차이만 있을 뿐 대부분의 로직은 비슷하고 결과 또한 같습니다.

개발자가 질의하고자 원했던 쿼리는 다음과 같습니다.

select * from emp where ename='SMITH'

 

로그 정보를 확인하여 어떻게 처리되었는지 확인해 보세요.

#1 쿼리

select

        e.empno as empno1_1_,

        e.comm as comm2_1_,

        e.deptno as deptno7_1_,

        e.ename as ename3_1_,

        e.hiredate as hiredate4_1_,

        e.job as job5_1_,

        e.mgr as mgr8_1_,

        e.sal as sal6_1_

from emp e

where e.ename='SMITH'


 

 

앨리어스의 과다사용(?)이 눈에 띄지만 의도한 쿼리를 사용하였다는 것을 알 수 있습니다. emp 테이블과 dept 테이블은 N:1 관계입니다. emp 테이블에 질의를 할 때 emp와의 연관관계를 살펴서 1에 해당하는 테이블이 존재하면 EAGER 로딩정책에 따라 관련 테이블의 데이터를 가져오기 위한 질의를 추가적으로 수행합니다. 따라서, deptno=20에 해당하는 dept 테이블의 정보를 구하기 위해서 #2 쿼리가 수행됩니다.

 

 

#2 쿼리

select

        d.deptno as deptno1_0_0_,

        d.dname as dname2_0_0_,

        d.loc as loc3_0_0_

from dept d

where d.deptno=20


 

 

연관관계 처리에서 dept 테이블과 관련된 쿼리는 더 이상 수행되지 않습니다. 이는 20번 부서에 속한 직원정보는 구하지 않는다는 것을 의미합니다. 왜냐하면 부서와 직원의 연관관계는 1:N이기 때문에 LAZY 로딩정책에 따라 부서에 속한 직원정보를 구하는 쿼리가 별도로 수행되지 않는 것입니다.

 

하지만 #1 쿼리 결과로 얻은 데이터 중 mgr 칼럼은 직속상관의 empno를 의미하므로 조회 대상 'SMITH'의 직속상관 데이터를 구하기 위해서 쿼리가 더 수행되어야 합니다. 이는 emp(직원) 테이블과 emp(직속상관) 테이블은 N:1 관계이기 때문입니다.

따라서 연관관계 N:1 에 기본 로딩정책 EAGER에 따라 직속상관 데이터를 구하는 #3 쿼리가 수행됩니다.

 

#3 쿼리

select

        e.empno as empno1_1_0_,

        e.comm as comm2_1_0_,

        e.deptno as deptno7_1_0_,

        e.ename as ename3_1_0_,

        e.hiredate as hiredate4_1_0_,

        e.job as job5_1_0_,

        e.mgr as mgr8_1_0_,

        e.sal as sal6_1_0_,

        d.deptno as deptno1_0_1_,

        d.dname as dname2_0_1_,

        d.loc as loc3_0_1_,

        e2.empno as empno1_1_2_,

        e2.comm as comm2_1_2_,

        e2.deptno as deptno7_1_2_,

        e2.ename as ename3_1_2_,

        e2.hiredate as hiredate4_1_2_,

        e2.job as job5_1_2_,

        e2.mgr as mgr8_1_2_,

        e2.sal as sal6_1_2_

from emp e left outer join dept d

on e.deptno=d.deptno left outer join emp e2

on e.mgr=e2.empno

where e.empno=7902

 


 

 

 

#1 쿼리에서 구한 'SMITH'의 상관을 가리키는 직원번호 7902를 사용하여 직속상관의 데이터를 구할 때 이용합니다. 7902에 해당하는 직원은 'FORD' 입니다.

 

EntityManager는 스마트해서 최소한의 쿼리를 사용하여 필요한 모든 데이터를 구하기 위해서 3개의 테이블 emp(직원), dept(부서), emp(직속상관) 테이블들을 조인하여 처리하는 것을 볼 수 있습니다. 조인쿼리를 사용하여 7902(FORD)의 정보와 FORD의 직속상관인 7566(JONES)의 정보를 구했습니다.

 

다음으로 7566(JONES)의 직속상관인 7839의 데이터를 구하기 위한 #4 쿼리가 수행됩니다. emp(직원) 테이블과 emp(직속상관) 테이블의 연관관계는 N:1 이므로 계속해서 직속상관 데이터를 구하기 위한 쿼리가 연속적으로 수행됩니다.

#4 쿼리

select

        e.empno as empno1_1_0_,

        e.comm as comm2_1_0_,

        e.deptno as deptno7_1_0_,

        e.ename as ename3_1_0_,

        e.hiredate as hiredate4_1_0_,

        e.job as job5_1_0_,

        e.mgr as mgr8_1_0_,

        e.sal as sal6_1_0_,

        d.deptno as deptno1_0_1_,

        d.dname as dname2_0_1_,

        d.loc as loc3_0_1_,

        e2.empno as empno1_1_2_,

        e2.comm as comm2_1_2_,

        e2.deptno as deptno7_1_2_,

        e2.ename as ename3_1_2_,

        e2.hiredate as hiredate4_1_2_,

        e2.job as job5_1_2_,

        e2.mgr as mgr8_1_2_,

        e2.sal as sal6_1_2_

 from emp e left outer join dept d

 on e.deptno=d.deptno left outer join emp e2

 on e.mgr=e2.empno

 where e.empno=7839

 




 

#3 쿼리에서 구한 7839 직원번호를 사용하여 'JONES'의 상관인 'KING'의 데이터를 구했습니다.

 

'KING'은 조직의 보스로서 자신이 조직도의 정점입니다. 더 이상 직속상관의 정보를 구하기 위한 쿼리를 수행할 필요가 없습니다. emp(직원), dept(부서) 테이블을 조인쿼리로 질의하면서 이미 'KING'이 속한 10번 부서의 정보를 구했으므로 역시나 dept 테이블을 별도로 조회하는 쿼리는 필요가 없습니다.

 

 

EmpDaoImpl. getByEname1 메소드 내 코드

query.select(emp).from(emp).where(emp.ename.eq("SMITH"));

 

위 메소드로 만들어지는 결과는 JPQL입니다. 이는 EntityManager에 의해서 SQL로 바뀌어 해당 데이터베이스에게 질의가 됩니다.

 

정리

#1 쿼리만을 개발자가 사용했지만 테이블의 연관관계에 따라 추가적으로 데이터를 구하기 위해서 자동으로 필요한 질의가 수행되는 모습을 살펴보았습니다. 개발자의 입장에서는 굉장히 편리한 기능입니다. 하지만 사용하지 않는 데이터를 매번 이렇게 연속적으로 쿼리가 수행되게 두는 것은 그리 현명한 판단이 아닐 것입니다.

 

퍼옴 : http://ojc.asia/bbs/board.php?bo_table=LecJpa&wr_id=341

728x90
반응형

'프로그램 > 자바' 카테고리의 다른 글

open api 국세청 사업자정보 진위확인  (0) 2021.12.14
자바로 PWA PUSH 만들기  (0) 2021.08.06
기본 Java 타입과 DB 필드 매핑  (0) 2021.08.04
사용자 정의 컬럼 추가하기  (0) 2021.05.25
Lombok 어노테이션  (0) 2021.05.24

댓글



"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."

loading