본문 바로가기

spring(스프링)

Querydsl 사용하기 (spring boot,maven)

반응형

Querydsl을 사용하는 이유 

JPA(Java Persistence Api)가 제공해주는 CRUD(Create Read Update Delete)를 사용한다고 하더라도

조회하는 데이터가 복잡해지면 복잡해질수록 JPQL(Java Persistence Query Language)가 필연적으로 사용하게 됩니다 

쿼리는 문자열로 이루워져있어서 코드를 읽기 힘들게 하고

컴파일 과정에서 오류를 발견하기 어렵고 결과가 나오기 전까지는 검증 또한 어렵습니다 

querydsl사용 함으로써 쿼리를 코드 형식으로 작성할 수 있고 

코드 형식으로 작성을 하기 때문에 사전에 오류를 먼저 캐치할수 있고 

IDE(Intergrated Development Enviroment)의 자동완성 기능을 사용할 수 있으며 

동적인 쿼리를 생성하는데 훨씬더 수월하게 할 수 있습니다 

 


설정 

maven pom.xml에 의존성 추가 

<dependency>
	<groupId>com.querydsl</groupId>
	<artifactId>querydsl-apt</artifactId>
	<version>${querydsl.version}</version>
	<scope>provided</scope>
</dependency>
<dependency>
	<groupId>com.querydsl</groupId>
	<artifactId>querydsl-jpa</artifactId>
	<version>${querydsl.version}</version>
</dependency>

플러그인 추가 

<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>

maven업데이트 실행

설정을 완료했습니다 Q타입 또한 생성이 되었을겁니다!

 


Querydsl 사용

 

먼저 JpaQueryFactory 설정을 해주어야 합니다

spring 에 빈등록을 해서 싱글톤으로 전역으로 사용할 수 있게 해줍시다 

또  entityMangerFactory는 어플리케이션에 하나씩만 생성이 되어야 합니다

@Configuration
public class QuerydslConfig {
    @PersistenceContext
    private EntityManager em;

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

EntityManger 는  @PersistenceContext(영속성 컨텍스트)는 영속선 컨텍스트 내에서 관리하고 있는 entity를 주입해주는 어노테이션이고 어플리케이션 동작과 동시에 스프링빈에 등록이 되어 있다고 합니다 

 

이제 예제를 위해 간단한 entity를 생성하겠습니다

@Getter
@Setter
@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue
    private long id;
    @Column(columnDefinition = "VARCHAR(16)")
    private String userId;
    @Column(columnDefinition = "VARCHAR(16)")
    private String username;

    public User(String userId, String username) {
        this.userId = userId;
        this.username = username;
    }
}

repository도 필요하겠죠

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}

이제 QuerydslRepository를 상속받아서 사용해보겠습니다 

import static com.example.blog.domain.QUser.user;
import com.example.blog.domain.User;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public class UserRepositorySupport extends QuerydslRepositorySupport {
    private final JPAQueryFactory queryFactory;

    public UserRepositorySupport(JPAQueryFactory queryFactory) {
        super(User.class);
        this.queryFactory = queryFactory;
    }

    public List<User> findByUserId(String userId){
        return queryFactory
                .selectFrom(user)
                .where(user.userId.eq(userId))
                .fetch();
    }
}

Quser 사용합니다 

내부에 static으로 정의되어있습니다 QUser의 user를 static으로 import해주시면 됩니다 

//물론 
Quser.user //사용가능합니다

 

 

이제 테스트를 해보도록 하겠습니다 

@SpringBootTest
class UserTest {
    @Autowired
    UserRepository userJpaRepository;

    @Autowired
    UserRepositorySupport userRepositorySupport;

    @Test
    public void queryDslTest() {
        userJpaRepository.deleteAll();
        User user = new User("testId", "testName");
        userJpaRepository.save(user);

        List<User> result = userRepositorySupport.findByUserId(user.getUserId());

        System.out.println(result.size());
        System.out.println(result.get(0).getUserId());
    }
}

 

결과

result.size()  =  1
result.get(0).getUserId = testId

 

 

직관적으로 보기위해 assertThat은 사용하지 않았습니다 

결과가 잘 나왔습니다 

 

하지만 위에 코드를 보시면 알겠지만 

 @Autowired
    UserRepository userJpaRepository;

    @Autowired
    UserRepositorySupport userRepositorySupport;

 

두개의 repository를 받아야 한다는 것입니다 

조금더 나은 코드로 수정을 해야겠네요 

두개의 코드를 하나로 합치겠습니다

 

먼저 support 클래스를 참고해서 

public interface UserRepositoryCustom {

    List<User> findByUserId(String userName);
}

custom 인터페이스를 하나 생성해줍니다 

구현 클래스도 생성을 해줍니다 

public class UserRepositoryImpl implements UserRepositoryCustom {
    private JPAQueryFactory queryFactory;

    public UserRepositoryImpl(JPAQueryFactory queryFactory) {
        super(User.class);
        this.queryFactory = queryFactory;
    }

    @Override
    public List<User> findByUserId(String userId) {
        return jpaQueryFactory
                .selectFrom(user)
                .where(user.userId.eq(userId))
                .fetch();
    }
}

그 뒤에 

@Repository
public interface UserRepository extends JpaRepository<User, Long>,UserRepositoryCustom {

}

다중 상속을 해주시면 userRepository에서 다 사용할 수 있게 됩니다 

부족한 부분이 있으시다면 댓글 주세요

반응형