결과 조회

fetch(): 리스트 조회, 데이터 없으면 빈 리스트를 반환한다

fetchOne(): 단건 조회

-> 결과가 없으면: null

-> 결과가 둘 이상이면 :com.querydsl.core.NonUniqueResultException 예외 발생

fetchFirst(): limit(1).fetchOne(), 처음 한 건을 조회한다 

fetchResults(): 페이징 정보 포함, total count 쿼리 추가 실행

fetchCount(): count 쿼리로 변경해서 count 수 조회 

내림차순,오름차순

nulls last: 데이터가 없을때 마지막으로 출력하는 것

 

ex)

.orderBy(member.username.asc(), member.age.desc())

.orderBy(member.username.asc().nullsLast())

페이징

-조회 건수 제한(offset,limit)

@Test
public void paging1() {
    List<Member> result = queryFactory
            .selectFrom(member)
			.orderBy(member.username.desc()) 
			.offset(1) //0부터 시작(zero index) 
			.limit(2) //최대 2건 조회
			.fetch();
    assertThat(result.size()).isEqualTo(2);
}

 

-전체 조회 수가 필요하면?

fetchResults()를 이용한다. total count 쿼리를 추가로 실행한다

count 쿼리가 실행됨으로써 성능에 문제를 줄 수 있다

@Test
public void paging2() {
    QueryResults<Member> queryResults = queryFactory
            .selectFrom(member)
            .orderBy(member.username.desc())
            .offset(1)
            .limit(2)
            .fetchResults(); ////
     
     //전체 갯수
    assertThat(queryResults.getTotal()).isEqualTo(4);
    
    //페이징 정보 확인
    assertThat(queryResults.getLimit()).isEqualTo(2);
    assertThat(queryResults.getOffset()).isEqualTo(1);
    
    //페이징 결과 확인
    assertThat(queryResults.getResults().size()).isEqualTo(2);
}

 

 

기본 검색 쿼리

@Test
public void search() {
    Member findMember = queryFactory
            .selectFrom(member)
            //where(member.username.eq("member1"),member.age.eq(10)).fetch()로 처리 가능
            .where(member.username.eq("member1")
                    .and(member.age.eq(10)))
            .fetchOne();
    assertThat(findMember.getUsername()).isEqualTo("member1");
}

select,from을 selectFrom으로 합칠 수 있다

검색 조건에서 .and() , .or()를 메서드 체인으로 연결할 수 있다

.and()는 파라미터로 처리할 수 있다 

Querydsl은 JPQL이 제공하는 모든 검색 조건을 제공한다 

member.username.eq("member1") // username = 'member1'
member.username.ne("member1") //username != 'member1'
member.username.eq("member1").not() // username != 'member1'
member.username.isNotNull() //이름이 is not null
member.age.in(10, 20) // age in (10,20)
member.age.notIn(10, 20) // age not in (10, 20)
member.age.between(10,30) //between 10, 30
member.age.goe(30) // age >= 30
member.age.gt(30) // age > 30
member.age.loe(30) // age <= 30
member.age.lt(30) // age < 30
member.username.like("member%") //like 검색 
member.username.contains("member") // like ‘%member%’ 검색 
member.username.startsWith("member") //like ‘member%’ 검색 
...

Querydsl 이란? 

JPQL 빌더이다 

장점

1. 자바 코드로 작성하기 때문에 컴파일 시점에 오류를 잡아준다. code assistance도 해준다 

2. 파라미터 바인딩을 자동으로 해준다

 

build.gradle에서 Querydsl 설정하기

buildscript {
	ext {
		queryDslVersion = "5.0.0"
	}
}
plugins {
	id 'org.springframework.boot' version '2.6.4'
	id 'io.spring.dependency-management' version '1.0.11.RELEASE'
	//querydsl 추가
	id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
	id 'java'

}

group = 'heyazoo1007'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-web'


	//querydsl 추가
	implementation "com.querydsl:querydsl-jpa:${queryDslVersion}"
	implementation "com.querydsl:querydsl-apt:${queryDslVersion}"

	compileOnly 'org.projectlombok:lombok'
	runtimeOnly 'com.h2database:h2'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.8'
}

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

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

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

Querydsl 코드 줄이기 전

@Test
public void startQuerydsl(){

    JPAQueryFactory queryFactory = new JPAQueryFactory(em);

    QMember m = new QMember("m");

    Member findMember = queryFactory.selectFrom(m)
            .from(m)
            .where(m.username.eq("member1"))
            .fetchOne();

    Assertions.assertThat(findMember.getUsername()).isEqualTo("member1");

    }

 

기본 Q-Type 활용

Q클래스 인스턴스를 사용하는 2가지 방법

QMember qMember = new QMember("m"); //별칭 직접 지정 
QMember qMember = QMember.member; //기본 인스턴스 사용

 

-QType은 static import로 쓸 것을 권장한다(QMember.member-> member)

Querydsl 코드 줄인 후 

JPAQueryFactory queryFactory;

@BeforeEach
public void before(){

    queryFactory= new JPAQueryFactory(em); //필드 레벨로 사용하기 
    ...
}

@Test
public void startQuerydsl(){
        
    Member findMember = queryFactory
            .selectFrom(member)
            .from(member)
            .where(member.username.eq("member1"))
            .fetchOne();

    Assertions.assertThat(findMember.getUsername()).isEqualTo("member1");

    }

 

-JPAQueryFactory를 필드로 제공했을 때 동시성 문제는 어떻게 해결하는지에 대해서

 

동시성 문제는 JPAQueryFactory를 생성할 때 제공하는 EntityManager에 달려있다. 

스프링 프레임워크는 여러 쓰레드에서 동시에 같은 EntityManager에 접근해도, 트랜잭션마다 별도의 영속성 컨텍스트를 제공하기 때문에 동시성 문제는 걱정하지 않아도 된다. 

 

 

+ Recent posts