[Spring JPA #16] 스프링 데이터 QueryDsl

2021. 3. 25. 23:48 Spring Data/Spring Data JPA

 

| QueryDsl이란

 

  • QueryDsl은 Type-Safe한 쿼리를 위한 스프링에서 제공하는 Domain Specific Language입니다.
  • SQL같이 문자로 Type Check가 불가능하고 실행하기 전까지 작동 여부를 확인 하기 어려운 부분을 보완하여 SQL을 Java로 Type-Safe하게 개발 할 수 있게 해주는 프레임워크입니다.
  • Repository 인터페이스에서 메서드명이 너무 길어지거나 메서드명으로 쿼리문을 만들기 까다로운 조건일 때 유용하게 쓰일 수 있습니다.

 

| QueryDsl Qdomain 생성하기

 

프로젝트 구조

├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │       └── tutorial
│   │   │           └── springevent
│   │   │               ├── Account.java
│   │   │               ├── AccountRepository.java
│   │   │               └── SpringEventApplication.java
│   │   └── resources
│   │       └── application.properties
│   └── test
│       └── java
│           └── com
│               └── tutorial
│                   └── springevent
│                       └── AccountRepositoryTest.java

 

application.properties

spring.jpa.properties.hibernate.format_sql=true
logging.level.org.hibernate.type.descriptor.sql=trace

 

의존성 관리

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>com.querydsl</groupId>
        <artifactId>querydsl-apt</artifactId>
    </dependency>
    <dependency>
        <groupId>com.querydsl</groupId>
        <artifactId>querydsl-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
        <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>

 

  • 위 maven 설정에서 <build> 부분은 Qdomain 이라고 부르는 자바 코드를 생성하는 플러그인입니다. QueryDsl을 통해 쿼리를 생성할 때 이 Qdomain 객체를 사용합니다. 생성된 QDomain 객체를 보면 실제 도메인 객체의 모든 필드에 대해 사용가능한 모든 operation을 호출하는 메서드들이 정의되어 있습니다.

소스 코드

@SpringBootApplication
public class SpringEventApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringEventApplication.class, args);
    }

}
@Entity
@Data
public class Account {

    @Id
    @GeneratedValue
    private Long id;

    private String username;

    private String firstName;

    private String lastName;
}
public interface AccountRepository extends JpaRepository<Account, Long>,
        QuerydslPredicateExecutor<Account> {
}
  • QuerydslPredicateExecutor는 이 Repository가 QueryDsl을 실행할 수 있는 인터페이스를 제공하는 역할을 합니다.

 

위 상태에서 mvn compile을 하면 target/generated-sources/java에 Account에 대한 Qdomain인 QAccount가 생성됩니다.

└── target
    ...
├── generated-sources
│   ├── annotations
│   └── java
│       └── com
│           └── tutorial
│               └── springevent
│                   └── QAccount.java
@Generated("com.querydsl.codegen.EntitySerializer")
public class QAccount extends EntityPathBase<Account> {

    private static final long serialVersionUID = 456320137L;

    public static final QAccount account = new QAccount("account");

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

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

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

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

    public QAccount(String variable) {
        super(Account.class, forVariable(variable));
    }

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

    public QAccount(PathMetadata metadata) {
        super(Account.class, metadata);
    }

}

 

| QueryDsl 예제

@RunWith(SpringRunner.class)
@DataJpaTest
public class AccountRepositoryTest {

    @Autowired
    AccountRepository accountRepository;

    @Test
    public void crud() {
        Account account = new Account();
        account.setFirstName("saelobi");
        account.setLastName("kimbs");
        accountRepository.save(account);

        Predicate predicate = QAccount.account
                .firstName.containsIgnoreCase("saelobi")
                .and(QAccount.account.lastName.startsWith("kim"));
        Optional<Account> one = accountRepository.findOne(predicate);
        assertThat(one.orElseThrow(() -> new EntityNotFoundException())
                .getFirstName()).isEqualTo("saelobi");
        assertThat(one.orElseThrow(() -> new EntityNotFoundException())
                .getFirstName()).isEqualTo("saelobi");
    }
}
  • 위와 같이 accountRepository를 통해서 QueryDsl을 사용할 수 있습니다. Repository 인터페이스에서 메서드명으로 쿼리를 만드는 방식에 비해 가독성이 좋고 또한 Type-Safe하기 때문에 컴파일 타임때 오타 등 어떤 문제가 발생했을 시 미리 알려줄 수 있으므로 버그를 추적하기에도 용이합니다.

 

https://www.inflearn.com/course/스프링-데이터-jpa



출처: https://engkimbs.tistory.com/828?category=772527 [새로비]