Spring boot With Querydsl

옛날부터 꼭 올려야 된다 생각하였지만….. 그렇게 하면… 너무 많아서 잠을 잘수가 없다..

코틀린 with QueryDsl 과거 코틀린편은 올렸으나 자바로 한 적이 없어서…. 이글을 쓴다.

1. Why QueryDsl

  1. Type-check가 불가능하다. -> SQL, JPQL은 문자열임
  2. 컴파일 시점에… 알수가 없다.
  3. 쿼리 실행이 어플리케이션에 실행되었을 때 아이고 저런.. 하며 후회한다.
  4. 그럼 어찌해야하느냐!! -> QueryDsl 또는 Jooq를 쓰자

QueryDsl -> 쓰면서 느끼는 점

  1. Sql이 클래스처럼 Type이 있어 type-safe하다
  2. 다이나미쿼리(동적쿼리)를 짜기 편하다.
  3. Jooq가 QueryDsl보다 편하지만 아직은 대중적이지 않다. 개인적으로 Jooq는 rdb로 통계쿼리 뽑아내는 부분은 짱이다.

2. 바로 실습

build.gradle (메이븐일 경우 다른데곳에서 찾아서….하시길..)

대충 아래처럼 추가라고 말했지만.. 이기준은 gradle 5이상에서의 셋팅이다.. 아.. 5버젼에서 처음 셋팅하느라 고생을 ….하였다. 빨리하고 자려고 했는데..

build.gradle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
plugins {
id 'org.springframework.boot' version '2.1.5.RELEASE'
id 'java'
id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
}



dependencies {

중략
...



compile("com.querydsl:querydsl-jpa") // querydsl
compile("com.querydsl:querydsl-apt") // querydsl
runtimeOnly 'mysql:mysql-connector-java'
compile('org.springframework.boot:spring-boot-starter-data-jpa')

...

중략


}


def querydslSrcDir = 'src/main/generated'

querydsl {
library = "com.querydsl:querydsl-apt"
jpa = true
querydslSourcesDir = querydslSrcDir
}

compileQuerydsl{
options.annotationProcessorPath = configurations.querydsl
}

configurations {
querydsl.extendsFrom compileClasspath
}

sourceSets {
main {
java {
srcDirs = ['src/main/java', querydslSrcDir]
}
}
}

application.yml

ddl 트루로 하자 구찮다.

1
2
3
4
5
6
7
8
9
10
spring: 
datasource:
url: jdbc:mysql://localhost:3306/study
username: root
password: password


jpa:
generate-ddl: true
hibernate.ddl-auto: create-drop

UserEntity.class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

@Data
@Entity(name = "users")
public class UserEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;

private String userId;
private String name;
private int age;

@Builder
public UserEntity(String userId, String name, int age){

this.userId = userId;
this.name = name;
this.age = age;

}

}

3. gradle build

아래와 같은 QClass가 위에서 명시한 src/main/generate아래에 생성되어진다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

import static com.querydsl.core.types.PathMetadataFactory.*;

import com.querydsl.core.types.dsl.*;

import com.querydsl.core.types.PathMetadata;
import javax.annotation.Generated;
import com.querydsl.core.types.Path;


/**
* QUserEntity is a Querydsl query type for UserEntity
*/
@Generated("com.querydsl.codegen.EntitySerializer")
public class QUserEntity extends EntityPathBase<UserEntity> {

private static final long serialVersionUID = 1472300146L;

public static final QUserEntity userEntity = new QUserEntity("userEntity");

public final StringPath age = createString("age");

public final NumberPath<Long> id = createNumber("id", Long.class);

public final StringPath name = createString("name");

public final StringPath userId = createString("userId");

public QUserEntity(String variable) {
super(UserEntity.class, forVariable(variable));
}

public QUserEntity(Path<? extends UserEntity> path) {
super(path.getType(), path.getMetadata());
}

public QUserEntity(PathMetadata metadata) {
super(UserEntity.class, metadata);
}

}

4. repository

아래의 설명을 읽어야하는이유! ( you must )

you must first define a fragment interface and an implementation for the custom functionality, as shown in the following example:

https://docs.spring.io/spring-data/jpa/docs/2.1.3.RELEASE/reference/html/#repositories.custom-implementations

참고하면 좋을 사항
https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl