상세 컨텐츠

본문 제목

13. JPA 이용한 커스텀 쿼리 만들기(QueryDSL)

Java/코딩의 신

by Gopythor 2023. 12. 23. 22:12

본문

728x90
반응형

JPA를 통해 커스텀 쿼리를 작성해보겠다.

지금까지는 레파지토리를 이용해서 findByUsesrname 등 예약된 키워드를 사용해서 데이터를 가져왔었음.

그러나 복잡한 조건에 있는 데이터를 어떻게 가져오는지 알아보겠음.

 

Spring Data JPA에서 샘플을 가져오겠다.

만든 메소드에 @Query 어노테이션을 사용해서 SQL과 비슷한 문법을 작성할 수 있음.

JPQL이다.

Like 조건이 있다. 복사를 해서 가져와보도록 함.

public interface UserRepository extends JpaRepository<User, Long> {

  @Query("select u from User u where u.firstname like %?1")
  List<User> findByFirstnameEndsWith(String firstname);
}

 

일반 SQL은 all을 선택할 때, *를 사용한다.

그러나 여기서는 u를 사용한다.(user)

username에 맞게 수정을 해보겠다.

username을 검색.

실제 사용구문
1. select * from table_name where title like '블로그%'
2. select * from table_name where title like '%블로그'
3. select * from table_name where title like '%블로그%'
 
1번 구문은 블로그로 시작되는 모든 값을 검색하여 가져오고
2번 구문은 블로그로 끝나는 모든 값을 검색하여 가져오고
3번 구문은 블로그가 들어있는 모든 값을 검색하여 가져옵니다.

 

username의 값을 가져올 것이다.

첫번째 파라미터라는 의미로 ?1.

 

이름도 findByUsernameQuery로 변경.

all 메소드 호출해보겠음.

호출해서 데이터를 가져옴.

boards 데이터도 같이 가져오고 있음.

알아보기 쉽게 하기 위해서 user 클래스에서 boards에 @JsonIgnore 설정.

board데이터가 나오지 않을 것임.

3명의 데이터가 잘 나오고 있음.

기존의 getBoards().size()는 삭제.

파라미터를 받아서 여러가지 방식으로 조회를 해보겠음.

method라는 파라미터를 받아보겠음.

@RequestParam을 작성하면 기본값으로 required가 true로 되어있어서 반드시 작성해야 한다.

required = false로 작성.

메소드에 따라서 여러가지 방식으로 조회를 해보겠다.

query라는 메소드로 왔다.

그러면 복사를 해서 아래 메소드로 호출.

어떤 문자열로 검색을 할지도 같이 받도록 하겠음.
TEXT값을 findByUsernameQuery에 넣어줬음.

기본적으로는 초기에 있었던 findAll을 실행함.

메소드가 query일 때에만, 방금 지정한 findByUsernameQuery가 호출이 된다.

아무 파라미터도 주지 않으면 처음과 동일하게 전체 사용자 데이터를 호출한다.

method=query를 주게 되면 아무런 결과값도 나타나지 않는다.

text 파라미터로 문자를 줘보도록 하겠다.

dong2가 포함된 회원이 나온다.

로그를 봐도 like 검색이 걸린 것을 볼 수 있다.

쿼리에 의해 데이터가 조회되는 것을 확인 했음.

두번째로 nativeQuery를 true로 지정하는 방법도 있다.

true로 지정하면 원하는 sql 문장을 입력할 수 있다.

nativeQuery를 else if에 추가하였다.

post man에서 native query를 날린다.

결과는 동일하다.

로그 어떤 문장이 실행됐는지 알 수 있음.

Select All로 실행이 됨.

아까는 User클래스의 컬럼들이 하나하나 지정이 됨.

다르게 호출이 됨.

네이티브 쿼리도 옵션값을 지정해서 날릴 수 있음.

해당 방법 이외에도 Querydsl을 이용할 수 있음.

 

 

많이 사용되는 방법임.

JPA 관련해서 설정하는 방법이 나와있음.

 

pom.xml에 추가.

 

plugin도 추가해줘야 함.

plugins에 껴줘라.

버전이 변수로 선언되어 있음.

버전도 지정 해줄 것임.

maven에서 버전 확인.

5.0.0 추가.

23년 12월 21일 기준으로도 5.0.0이 최신

QuerydslPredicateExecutor가 있다.

사전에 지정된 인터페이스가 있다.

extends에 끼워 넣으면 된다.

UserRepository에 끼워 넣어라.

메소드 명은 동일하다.

Predicate의 조건절을 생성할 수 있음.

 

querydsl에 있는 Predicate를 import함.

user를 쓰고 있는데, 사용자 컬럼명이다.

equalsIgnoreCase.

대소문자 구분없이 dave 라는 이름을 가지고 있으면서, lastname은 mathews로 시작하는 사용자를 가져와라.

firstname과 lastname은 컬럼명이다.

 

QCustomer를 선언함.

Q + 클래스명을 이용하면 테이블 데이터를 이용할 수 있다.

 

사용하기 위해 주석처리 함.

메이븐 컴파일 필요.

모델에서 정한 엔티티 클래스들

pom.xml 플러그인에 복사해서 붙여 넣었다.

컬럼 정보를 사용할 수 있게 자동으로 생성됨.

Quser로 수정.

username으로 수정.

like검색은 contains이다.

findAll이 predicate를 받을 수 있게 되었음.

return 타입.

users에 담으려고 하니 안 담김.

Iterable임.

List의 부모가 Iterable이다.

리턴을 Iterable로 한다.

보면 에러가 난다.

해당 패키지를 찾을 수 없다고 함.

자바 버전에 관련된 에러이다.

1.8로 변경

바뀌고나면 clean, compile을 해라.

querydsl로도 검색이 됨.

검색이 되서 user데이터가 들어옴.

sql과 비슷하게 조건문을 만들 수 있음.

where 조건과 비슷하게 계속 만들 수 있음.

 

if문 이용해서 특정 조건일 때에만 특정 조건을 주는 것도 가능.

BooleanExpression을 따라가보면 Predicate 인터페이스다.

그래서 Predicate에 담을 수 있다.

가장 간단하게 queryDSL을 이용해서 조회하는 방법을 알아봄.

 

User레파지토리를 확장할 수 있음.

CustomizedUserRepository 인터페이스 하나 생성.

메소드 생성.

//Your custom implementation에 구현을 함.

주의해야 할 점이 impl postfix.

구현체가 Impl로 끝나야 함.

CustomizedUserRepositoryImpl

 

 

끼워넣으면 지정한 메소드를 불러올 수 있음.

CustomizedUserRepository를 작성함.

findByUsernameCustom(User user);

 

ALT + ENTER 하면 인터페이스에 작성한 오버라이드 코드를 작성할 수 있음.

인텔리제이에서 자동완성해줌.

해당 코드에 원하는 쿼리를 작성할 수 있음.

어떻게 작성하라는 예제가 없음.

알아서 작성.

spring-data-examples에 예시가 있음.

Custom

EntityManager를 이용해서 데이터를 가져오고 있음.

EntityManager를 이용해서 데이터를 가져오는 방법이 굉장히 많다.

메뉴얼에서도 무엇을 쓰라고는 이야기를 안했다.

가장 간단하고 편한 것을 쓰면 된다.

 

Querydsl로 똑같이 날리겠다.

UserApiController에서는 조건절만 이용해서 findAll에 넘겼었다.

전부다 복사해서

QUser로 변환.

파라미터로 entityManager를 넘긴다.

파라미터로 user를 받았다.

username으로 받겠다.

fetch는 list로 반환한다.

repository에서 list반환으로 바꿈.

users반환.

호출을 해보도록 함.

querydslCustom으로 생성.

UserRepository에 CustomizedUserRepository 추가.

결과값이 나옴.

정의한 메소드에 의해서 데이터가 출력이 됨.

jdbc 템플릿을 이용할 수도 있음.

소스대로 하지 않고 스프링 홈페이지에 있는 방법대로 해볼 것임.

JDBC 사용하는 방법이 있음.

해당 방법이 간단해보여서 해당 방법으로 하는 것임.

방법이 워낙 많음.

프로젝트마다 다양한 방식으로 데이터를 가져오고 있음.

Impl에 JdbcTemplate Autowired 함.

    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    @Autowired
    JdbcTemplate jdbcTemplate;

Autowired 에러가 발생하여 어노테이션 추가하였음.

findByUsernameJdbc를 생성해보겠음.

Impl에 Override하도록 함.

NativeSQL을 이용해서 select를 하도록 함.

해당 방법보다 좀더 간단하게 날릴 수 있다.

BeanPropertyRowMapper를 이용하면 클래스를 통체로 받을 수 있음.

해당 방식으로 쿼리를 날려보도록 함.

import org.springframework.jdbc.core.BeanPropertyRowMapper;
	
    public Customer findByCustomerId2(Long id) {

        String sql = "SELECT * FROM CUSTOMER WHERE ID = ?";

        return (Customer) jdbcTemplate.queryForObject(
			sql, 
			new Object[]{id}, 
			new BeanPropertyRowMapper(Customer.class));

    }

단일건 조회

https://mkyong.com/spring/spring-jdbctemplate-querying-examples/

 

여러건 조회, 리스트

    public List<Customer> findAll() {

        String sql = "SELECT * FROM CUSTOMER";

        List<Customer> customers = jdbcTemplate.query(
                sql,
                new BeanPropertyRowMapper(Customer.class));

        return customers;
    }

 

핵심은 BeanPropertyRowMapper를 이용해서 가져오는 것.

Users로 바꾸고 SQL은 직접 선언하도록 함.

username like %?%

지정한 user클래스의 정보를 사용할 수는 없지만, 원하는 쿼리를 마음껏 날릴 수 있음.

jdbc로 지정함.

send를 했는데 에러가 발생함.

SQL 문법에 맞지 않음.

지금 파라미터를 넘기지 않았음.

new Object[]를 이용해서 파라미터를 넘길 수 있음.

다시 실행을 해볼 것임.

마찬가지로 에러가 발생했음.

%를 감싸줘볼것임.

전달한 파라미터에 붙여줘야 함.

https://youtu.be/8zjLIsqt8so?si=hWgYDfzW8G7N6rMn

728x90
반응형

관련글 더보기

댓글 영역