[Spring JPA #16] 스프링 데이터 QueryDsl
| 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하기 때문에 컴파일 타임때 오타 등 어떤 문제가 발생했을 시 미리 알려줄 수 있으므로 버그를 추적하기에도 용이합니다.
'Spring Data > Spring Data JPA' 카테고리의 다른 글
[Spring JPA #20] 스프링 부트 Spring JPA 엔티티 저장 메커니즘 (0) | 2021.03.26 |
---|---|
[Spring JPA #19] 스프링 데이터 HATEOAS (0) | 2021.03.26 |
[Spring JPA #18] 스프링 데이터 Pageable과 Sort (0) | 2021.03.26 |
[Spring JPA #17] 스프링 데이터 DomainClassConverter (0) | 2021.03.26 |
[Spring JPA #15] 스프링 데이터 도메인 이벤트 (0) | 2021.03.25 |
[Spring JPA #14] 스프링 데이터 커스텀 리포지터리 만들기 (0) | 2021.03.25 |
[Spring JPA #13] 스프링 데이터 쿼리 만들기 (0) | 2021.03.25 |
[Spring JPA #12] 스프링 데이터 Null 체크 (0) | 2021.03.25 |