스프링

 

중급자를 위해 준비한
[백엔드, 웹 개발] 강의입니다.

Querydsl의 기초부터 실무 활용까지, 한번에 해결해보세요!

✍️
이런 걸
배워요!

Querydsl을 기초부터 실무활용까지 한번에 배울 수 있습니다.

단순한 기능 설명을 넘어 실무활용 노하우를 배울 수 있습니다.

JPA를 사용할 때 동적 쿼리와 복잡한 쿼리 문제를 해결할 수 있습니다.

복잡한 쿼리, 동적 쿼리는 이제 안녕! 
Querydsl로 자바 백엔드 기술을 단단하게.

???? 본 강의는 로드맵 과정입니다.

  • 본 강의는 자바 백엔드 개발의 실전 코스를 완성하는 마지막 강의입니다. 스프링 부트와 JPA 실무 완전 정복 로드맵을 우선 확인해주세요. (링크)

 

 

강좌 

https://www.inflearn.com/course/querydsl-실전#

 

 

강의자료

https://github.com/braverokmc79/jpa-basic-lecture-file2

 

 

 

 

소스 :

https://github.com/braverokmc79/jpa-querydsl

 

 

 

 

 

 

 

 

 

 

[1] Querydsl 소개

 

 

1.소개

 

강의 :

https://www.inflearn.com/course/lecture?courseSlug=querydsl-실전&unitId=27939&tab=curriculum

 

 

 

 

2.강의자료

 

강의 :

https://www.inflearn.com/course/lecture?courseSlug=querydsl-실전&unitId=30112&tab=curriculum

 

 

 

 

 

 

[2] 프로젝트 환경설정

 

 

3.프로젝트 생성

 

강의 :

https://www.inflearn.com/course/lecture?courseSlug=querydsl-실전&unitId=30114&tab=curriculum

 

프로젝트 생성
스프링 부트 스타터(https://start.spring.io/)

 

 

 

 

Querydsl 스프링 부트 3.0 설정은 다음을 참고해주세요.
https://www.inflearn.com/chats/700670

 


스프링 부트 3.0 관련 자세한 내용은 다음 링크를 확인해주세요:

https://bit.ly/springboot3

 

 

강좌 Gradle 전체 설정

plugins {
    id 'org.springframework.boot'
    version '2.2.2.RELEASE'
    id 'io.spring.dependency-management'
    version '1.0.8.RELEASE'
    id 'java'
}
group = 'study'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}
repositories {
    mavenCentral()
}
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'com.h2database:h2'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
}
test {
    useJUnitPlatform()
}

 

 

 

현재 나의 Gradle 전체 설정

plugins {
	id 'java'
	id 'org.springframework.boot' version '2.7.9'
	id 'io.spring.dependency-management' version '1.0.15.RELEASE'
}

group = 'study'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.7'


	compileOnly 'org.projectlombok:lombok'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	runtimeOnly 'com.h2database:h2'
	runtimeOnly 'com.mysql:mysql-connector-j'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
	useJUnitPlatform()
}

 

 

 

동작 확인


기본 테스트 케이스 실행


스프링 부트 메인 실행 후 에러페이지로 간단하게 동작 확인(`http://localhost:8080')


테스트 컨트롤러를 만들어서 spring web 동작 확인(http://localhost:8080/hello)

 

 

 

테스트 컨트롤러

package study.querydsl.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello() {
        return "hello!";
    }
}

 

 

IntelliJ Gradle 대신에 자바로 바로 실행하기


최근 IntelliJ 버전은 Gradle로 실행을 하는 것이 기본 설정이다. 이렇게 하면 실행속도가 느리다. 다음과
같이 변경하면 자바로 바로 실행하므로 좀 더 빨라진다.

 

1. Preferences Build, Execution, Deployment Build Tools Gradle
2. Build and run using: Gradle IntelliJ IDEA
3. Run tests using: Gradle IntelliJ IDEA

 

 

 

롬복 적용
1. Preferences plugin lombok 검색 실행 (재시작)
2. Preferences Annotation Processors 검색 Enable annotation processing 체크 (재시작)
3. 임의의 테스트 클래스를 만들고 @Getter, @Setter 확인

 

 

 

 

 

 

=> 빌드를 인텔리제이로 변경

셋팅 -> build 검색 후  --> 그래들 build  -> 설정 

 

=> 롬복 적용

 

=> 인텔리제이 스프링부트 자동빌드 적용

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

4.Querydsl 설정과 검증

 

강의 :

https://www.inflearn.com/course/lecture?courseSlug=querydsl-실전&unitId=30115&tab=curriculum

 

 

 

1)  build.gradle

//querydsl 추가
buildscript {
	ext {
		queryDslVersion = "5.0.0"
	}
}

plugins {
	id 'java'
	id 'org.springframework.boot' version '2.7.9'
	id 'io.spring.dependency-management' version '1.0.15.RELEASE'
	//querydsl 추가
	id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
}

group = 'study'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.7'
	//querydsl 추가
	implementation "com.querydsl:querydsl-jpa:${queryDslVersion}"
	implementation "com.querydsl:querydsl-apt:${queryDslVersion}"

	compileOnly 'org.projectlombok:lombok'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	runtimeOnly 'com.h2database:h2'
	runtimeOnly 'com.mysql:mysql-connector-j'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
	useJUnitPlatform()
}

//querydsl 추가 시작
def querydslDir = "$buildDir/generated/querydsl"

querydsl {
	jpa = true
	querydslSourcesDir = querydslDir
}
sourceSets {
	main.java.srcDir querydslDir
}
compileQuerydsl{
	options.annotationProcessorPath = configurations.querydsl
}
configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
	querydsl.extendsFrom compileClasspath
}
//querydsl 추가 끝

 

 

 

 

 

 

2) AppConfig

import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.persistence.EntityManager;

@Configuration
@RequiredArgsConstructor
public class AppConfig {

    private final EntityManager em;

    @Bean
    public JPAQueryFactory queryFactory() {
        return new JPAQueryFactory(em);
    }

}

 

 

 

 

설정후 그래드를 업그레이드 및 빌드처리하면 다음 화면과 같이  build 파일에 Q Entity 파일들이 생성된다.

 

 

 

 

 

 

 

 

 

3) Querydsl 환경설정 검증

 

이미지 크게

 

 


검증용 엔티티 생성

 

package study.querydsl.entity;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
@Getter @Setter
public class Hello {
 @Id @GeneratedValue
 private Long id;
}

 

 

 

검증용 Q 타입 생성
Gradle IntelliJ 사용법
Gradle Tasks build clean
Gradle Tasks other compileQuerydsl

 


Gradle 콘솔 사용법
./gradlew clean compileQuerydsl

 

 

Q 타입 생성 확인


build generated querydsl
study.querydsl.entity.QHello.java 파일이 생성되어 있어야 함

 

 

참고: Q타입은 컴파일 시점에 자동 생성되므로 버전관리(GIT)에 포함하지 않는 것이 좋다.

앞서 설정에서  생성 위치를 gradle build 폴더 아래 생성되도록 했기 때문에 이 부분도 자연스럽게 해결된다.

(대부분 gradle build 폴더를 git에 포함하지 않는다.)

 

 

 

 

테스트 케이스로 실행 검증

 

package study.querydsl;

import com.querydsl.jpa.impl.JPAQueryFactory;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Rollback;
import org.springframework.transaction.annotation.Transactional;
import study.querydsl.entity.Hello;
import study.querydsl.entity.QHello;

import javax.persistence.EntityManager;

@SpringBootTest
@Transactional
@Rollback(value = false)
class ApplicationTests {

	@Autowired
	EntityManager em;

	@Test
	void contextLoads() {
		Hello hello=new Hello();
		em.persist(hello);


		JPAQueryFactory query=new JPAQueryFactory(em);
		//QHello qHello=new QHello("h");
		QHello qHello=QHello.hello;  //Querydsl Q타입 동작 확인
		Hello result =query.selectFrom(qHello)
				.fetchOne();

		Assertions.assertThat(result).isEqualTo(hello);
		//lombok 동작 확인(hello.getId());
		Assertions.assertThat(result.getId()).isEqualTo(hello.getId());
	}

}

 

 

AppConfig 클래스 파일을 설정하면 다음과 같이 사용가능

package study.querydsl;

import com.querydsl.jpa.impl.JPAQueryFactory;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Rollback;
import org.springframework.transaction.annotation.Transactional;
import study.querydsl.entity.Hello;
import study.querydsl.entity.QHello;

import javax.persistence.EntityManager;

@SpringBootTest
@Transactional
@Rollback(value = false)
class ApplicationTests {

	@Autowired
	EntityManager em;


	@Autowired
	JPAQueryFactory jpaQueryFactory;




	@Test
	void contextLoads2() {
		Hello hello=new Hello();
		em.persist(hello);


		QHello qHello=QHello.hello;
		Hello result =jpaQueryFactory.selectFrom(qHello).fetchOne();

		Assertions.assertThat(result).isEqualTo(hello);
		//lombok 동작 확인(hello.getId());
		Assertions.assertThat(result.getId()).isEqualTo(hello.getId());
	}
	
}

 

 

 

 

 

 

Querydsl Q타입이 정상 동작하는가?
lombok이 정상 동작 하는가?
> 참고: 스프링 부트에 아무런 설정도 하지 않으면 h2 DB를 메모리 모드로 JVM안에서 실행한다

 

 

 

4) 사용예

 

public List<Order> findAll(OrderSearch orderSearch){
    System.out.println("orderSearch = " + orderSearch);
  return em.createQuery("select o  from Order o join o.member m  " +
                  " where  o.status = :status " +
                  " and m.name like :name ", Order.class)
             .setParameter("status", orderSearch.getOrderStatus())
             .setParameter("name", orderSearch.getMemberName())
             //.setFirstResult(10)
             .setMaxResults(1000) //최대 1000건
             .getResultList();
}

 

package jpabook.jpashop.repository;
 
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import jpabook.jpashop.domain.Order;
import jpabook.jpashop.domain.OrderStatus;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;
 
import java.util.List;
 
import static jpabook.jpashop.domain.QMember.member;
import static jpabook.jpashop.domain.QOrder.order;
 
@Repository
@RequiredArgsConstructor
public class OrderRepository {
 
    private  final JPAQueryFactory query;
 
     
    public List<Order> findAll(OrderSearch orderSearch){
 
        return query.select(order)
                .from(order)
                .join(order.member, member)
                .where(statusEq(orderSearch.getOrderStatus()), nameLike(orderSearch.getMemberName()))
                .limit(1000)
                .fetch();
    }
 
 
    //주문자 이름 확인
    private BooleanExpression nameLike(String memberName){
        if(!StringUtils.hasText(memberName)){
            return  null;
        }
        return member.name.like(memberName);
    }
 
 
 
 
    //주문 상태
    private BooleanExpression statusEq(OrderStatus statusCond){
        if(statusCond==null){
            return  null;
        }
        return order.status.eq(statusCond);
    }
 
 
 
 
}

 

 

 

 

 

 

 

 

5.라이브러리 살펴보기

 

강의 :

https://www.inflearn.com/course/lecture?courseSlug=querydsl-실전&unitId=30116&tab=curriculum

 

 

gradle 의존관계 보기
./gradlew dependencies --configuration compileClasspath

 

 

 

Querydsl 라이브러리 살펴보기
querydsl-apt: Querydsl 관련 코드 생성 기능 제공
querydsl-jpa: querydsl 라이브러리

 

 

 

스프링 부트 라이브러리 살펴보기
spring-boot-starter-web
spring-boot-starter-tomcat: 톰캣 (웹서버)
spring-webmvc: 스프링 웹 MVC
spring-boot-starter-data-jpa
spring-boot-starter-aop
spring-boot-starter-jdbc
HikariCP 커넥션 풀 (부트 2.0 기본)
hibernate + JPA: 하이버네이트 + JPA
spring-data-jpa: 스프링 데이터 JPA
spring-boot-starter(공통): 스프링 부트 + 스프링 코어 + 로깅
spring-boot
spring-core
spring-boot-starter-logging
logback, slf4j
 

 

 

 

테스트 라이브러리
spring-boot-starter-test
junit: 테스트 프레임워크, 스프링 부트 2.2부터 junit5( jupiter ) 사용

과거 버전은 vintage
mockito: 목 라이브러리


assertj: 테스트 코드를 좀 더 편하게 작성하게 도와주는 라이브러리
https://joel-costigliola.github.io/assertj/index.html
spring-test: 스프링 통합 테스트 지원

 

 

핵심 라이브러리
스프링 MVC
JPA, 하이버네이트
스프링 데이터 JPA
Querydsl


기타 라이브러리
H2 데이터베이스 클라이언트
커넥션 풀: 부트 기본은 HikariCP
로깅 SLF4J & LogBack
테스트

 

 

 

 

 

 

 

 

 

 

 

 

6.H2 데이터베이스 설치

 

강의 :

https://www.inflearn.com/course/lecture?courseSlug=querydsl-실전&unitId=30117&tab=curriculum

 

 

 

 

 

개발이나 테스트 용도로 가볍고 편리한 DB, 웹 화면 제공
https://www.h2database.com

 

다운로드 및 설치
h2 데이터베이스 버전은 스프링 부트 버전에 맞춘다.
권한 주기: chmod 755 h2.sh

 


데이터베이스 파일 생성 방법
jdbc:h2:~/querydsl (최소 한번)
~/querydsl.mv.db 파일 생성 확인
이후 부터는 jdbc:h2:tcp://localhost/~/querydsl 이렇게 접속

 

 

> 참고: H2 데이터베이스의 MVCC 옵션은 H2 1.4.198 버전부터 제거되었습니다. 이후 부터는 옵션 없이 사용하면 됩니다.

 

 

주의: 가급적 안정화 버전을 사용하세요. 1.4.200 버전은 몇가지 오류가 있습니다.
> 현재 안정화 버전은 1.4.199(2019-03-13) 입니다.
> 다운로드 링크: https://www.h2database.com/html/download.html

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

7.스프링 부트 설정 - JPA, DB

 

강의 :

https://www.inflearn.com/course/lecture?courseSlug=querydsl-실전&unitId=30118&tab=curriculum

 

 

 

application.yml

spring:
 datasource:
 url: jdbc:h2:tcp://localhost/~/querydsl
 username: sa
 password:
 driver-class-name: org.h2.Driver
 jpa:
 hibernate:
 ddl-auto: create
 properties:
 hibernate:
# show_sql: true
 format_sql: true
logging.level:
 org.hibernate.SQL: debug
# org.hibernate.type: trace

 

 

application.properties

#yaml 전환사이트 https://mageddo.com/tools/yaml-converter
#터미널 코드 컬러 출력 설정
spring.output.ansi.enabled=always


#Springboot auto build
spring.devtools.livereload.enabled=true
spring.devtools.restart.enabled=true


spring.driver-class-name=org.h2.Driver
spring.datasource.url= jdbc:h2:tcp://localhost/~/querydsl
spring.datasource.username=sa
spring.datasource.password=


spring.jpa.hibernate.ddl-auto= create
#spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
#spring.jpa.properties.hibernate.default_batch_fetch_size=100

#페이지크기
spring.data.web.pageable.default-page-size=3 
# 최대 페이지 크기
spring.data.web.pageable.max-page-size=2000 


logging.level.org.hibernate.SQL=debug
logging.level.org.hibernate.type=trace

 

 

spring.jpa.hibernate.ddl-auto: create
이 옵션은 애플리케이션 실행 시점에 테이블을 drop 하고, 다시 생성한다.

 

 

 

> 참고: 모든 로그 출력은 가급적 로거를 통해 남겨야 한다.
> show_sql : 옵션은 System.out 에 하이버네이트 실행 SQL을 남긴다.
> org.hibernate.SQL : 옵션은 logger를 통해 하이버네이트 실행 SQL을 남긴다.

 

 

 

 

쿼리 파라미터 로그 남기기
로그에 다음을 추가하기 org.hibernate.type : SQL 실행 파라미터를 로그로 남긴다.


외부 라이브러리 사용
https://github.com/gavlyukovskiy/spring-boot-data-source-decorator

 

 

스프링 부트를 사용하면 이 라이브러리만 추가하면 된다

	
implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.8'

 

> 참고: 쿼리 파라미터를 로그로 남기는 외부 라이브러리는 시스템 자원을 사용하므로, 개발 단계에서는
편하게 사용해도 된다. 하지만 운영시스템에 적용하려면 꼭 성능테스트를 하고 사용하는 것이 좋다.

 

 

 

 

★쿼리 파라미터 로그 남기기 - 스프링 부트 3.0

 

p6spy-spring-boot-starter 라이브러리는 현재 스프링 부트 3.0을 정상 지원하지 않는다.


스프링 부트 3.0에서 사용하려면 다음과 같은 추가 설정이 필요하다

 

1) org.springframework.boot.autoconfigure.AutoConfiguration.imports 파일 추가

src/resources/META-INF/spring/
org.springframework.boot.autoconfigure.AutoConfiguration.imports

 

com.github.gavlyukovskiy.boot.jdbc.decorator.DataSourceDecoratorAutoConfigurati
on

 

폴더명:   src/resources/META-INF/spring

 

파일명:   org.springframework.boot.autoconfigure.AutoConfiguration.imports

 

 

 

2)  spy.properties 파일 추가

 

src/resources/spy.properties

appender=com.p6spy.engine.spy.appender.Slf4JLogger

 

이렇게 2개의 파일을 추가하면 정상 동작한다.

 

 

메이븐

		<dependency>
			<groupId>com.github.gavlyukovskiy</groupId>
			<artifactId>p6spy-spring-boot-starter</artifactId>
			<version>1.9.0</version>
		</dependency>

 

 

 

 

 

 

 

 

 

 

 

[3] 예제 도메인 모델

 

 

8.예제 도메인 모델과 동작확인

 

강의 :

https://www.inflearn.com/course/lecture?courseSlug=querydsl-실전&unitId=30120&tab=curriculum

 

 

참고: 스프링 데이터 JPA와 동일한 예제 도메인 모델을 사용합니다. 스프링 데이터 JPA 강의를 들으신 분은
엔티티 코드만 작성하고 다음으로 넘어가도 됩니다.
예제 도메인 모델과 동작확인

 

 

Member 엔티티

package study.querydsl.entity;


import lombok.*;

import javax.persistence.*;

@Entity
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@ToString(of = {"id", "username" , "age"})
public class Member {

    @Id
    @GeneratedValue
    @Column(name="member_id")
    private Long id;
    private String username;
    private int age;


    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="team_id")
    private Team team;


    public Member(String username) {
        this(username, 0);
    }

    public Member(String username, int age) {
        this(username, age, null);
    }

    public Member(String username, int age, Team team){
        this.username=username;
        this.age=age;
        if(team!=null){
            changeTeam(team);
        }
    }

    private void changeTeam(Team team) {
        this.team=team;
        team.getMembers().add(this);
    }


}

 

 

롬복 설명


@Setter: 실무에서 가급적 Setter는 사용하지 않기


@NoArgsConstructor AccessLevel.PROTECTED: 기본 생성자 막고 싶은데, JPA 스팩상  PROTECTED로 열어두어야 함


@ToString은 가급적 내부 필드만(연관관계 없는 필드만)


changeTeam() 으로 양방향 연관관계 한번에 처리(연관관계 편의 메소드)

 

 

 

 

 

 

Team 엔티티

package study.querydsl.entity;


import lombok.*;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@ToString(of = {"id", "name" })
public class Team {

    @Id
    @GeneratedValue
    @Column(name="team_id")
    private Long id;
    private String name;

    @OneToMany(mappedBy = "team")
    private List<Member> members=new ArrayList<>();

    public Team(String name){
        this.name=name;
    }

}

 

 

Member와 Team은 양방향 연관관계, Member.team 이 연관관계의 주인, Team.members 는 연관관계의
주인이 아님, 따라서 Member.team 이 데이터베이스 외래키 값을 변경, 반대편은 읽기만 가능

 

 

데이터 확인 테스트

package study.querydsl.entity;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Commit;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
@Transactional
//@Commit
class MemberTest {

    @Autowired
    EntityManager em;


    @Test
    public void testEntity(){
        Team teamA =new Team("teamA");
        Team teamB =new Team("teamB");
        em.persist(teamA);
        em.persist(teamB);

        Member member1=new Member("member1", 10, teamA);
        Member member2=new Member("member2", 20, teamA);

        Member member3=new Member("member3", 30, teamB);
        Member member4=new Member("member4", 40, teamB);

        em.persist(member1);
        em.persist(member2);
        em.persist(member3);
        em.persist(member4);

        //초기화
        em.flush();
        em.clear();

        List<Member> members = em.createQuery("select m from Member m ", Member.class).getResultList();

        for (Member member :members){
            System.out.println("member = " + member);
            System.out.println("-> member.team" +member.getTeam());
        }
    }


}

 

가급적 순수 JPA로 동작 확인 (뒤에서 변경)


db 테이블 결과 확인


지연 로딩 동작 확인

 

 

 

 

 

 

 

 

 

 

about author

PHRASE

Level 60  라이트

잣눈도 모르고 조복(朝服)을 마른다 , 기본적이거나 기초적인 것도 모르고 가장 어려운 일을 하고자 함을 빗대어 이르는 말.

댓글 ( 4)

댓글 남기기

작성