# 3. Spring Data JPA 를 이용한 쿼리 연습

## 쿼리 메소드 리턴 타입

Page , Slice, List 같은 Collection 형태가 된다.

repository에 작성할때, 쿼리 예시

```
public List<Board> findBoardByTitle(String title);
```

find + { 찾고자 하는 클래스 } + By + { 무엇으로 찾을 지 } (type)

## findBy를 통해 특정 칼럼을 처리하는 법

1\.

```
Collection<T> findBy + 속성 이름(속성 타입)
ex)
public Collection<Board> findByWriter(String writer);
```

2\.

```
@Test
public void testByWriter() {
    Collection<Board> results = repo.findByWriter("user00");

    reuslts.forEach(
        board -> System.out.println(board)
    );
}
```

## Page import 에 해깔림이 있으시는 분

```
- Pageable = import org.springframework.data.domain.Pageable;
- PageRequest = import org.springframework.data.domain.PageRequest;
- Page = import org.springframework.data.domain.Page;
```

## JPA Paging 이 필요할 때 사용하려면

```
ex)
public List<Board> findByBnoGreaterThanOrderByBnoDesc(Long bno,Pageable paging)
```

코드는 기존과 동일하지만, 파라미터에 Pageable이 적용되었고 Collection<> 에서 List<> 로 변경되었습니다.

* Pageable 인터페이스가 적용되는 경우는 리턴타입이 Slice, Page, List 타입이다.

## 페이징에 가장 많이 사용되는 PageRequest

PageRequest는 SpringBoot 2.0으로 넘어오면서 PageRequest.of()를 사용하고 있다.

## JPA 와 Spring MVC와 연동할 때 Page 타입을 쓰자.

Page 타입을 이용하면 Spring MVC와 연동할 때 상당한 편리함을 주는데 지금부터 알아보자.

```
public interface BoardRepository extends CrudRepository<Board,Long>{

    public Page<Board> findByBnoGreaterThan(Long bno,Pageable paging);
}
```

```
ex) Test java case
@Test
public void testBnoPagingSort(){
    //Spring boot 2.0
    Pageable paging = PageRequest.of(0,10,Sort.Direction.ASC,"bno");

    Page<Board> result = repo.findByBnoGreaterThan(0L,paging);

    System.out.println(result.getSize());
    System.out.println(result.getTotalPages());
    System.out.println(result.getTotlalElements());
    System.out.println(result.nextPageable());

    List<Board> list = result.getContent();
    list.forEach(board -> System.out.prinln(board));
}
```

위 코드를 실행하게 되면 아래처럼 결과가 나온다.

```
10
20
200
Page request [number:1, size 10, sort: bno: ASC]
Board(bno=1 ...) => //getContent를 통해 객체를 받아올수 있다.
```

## @Query 이용법

왜? @Query 어노테이션을 사용할까?

PK(Primary Key)를 이용하여 Full table Scan을 하게 되면 모든 데이터에 대해 검색을 통해 처리되기 때문에 성능이 나쁠 수 있다는 견해가 있다. (하지만 병렬 처리가 효과적으로 처리되면 더 빠른 경우도 있음)

'where bno > 0 ' 과 같은 표현이 JPA 메소드에 표현하기에는 어색함 -> @query 를 사용하게 됨

```
    @Query("Select b from board b where b.title like %?1% and b.bno > 0 order by b.bno desc")
    public List<Board> findByTitle(String title);
```

%?1%을 살펴보면 '?'는 JDBC의 PreparedStatement와 동일 '?1'은 첫번째로 전달되는 파라미터를 의미한다.

* 실행결과 Query

  ```
  Hibernate: select board0_.bno as bno1_0_, board0_.content as content2_0_, board0_.regdate as regdate3_0_, board0_.title as title4_0_, board0_.updatedate as updateda5_0_, board0_.writer as writer6_0_ from tbl_boards board0_ where (board0_.title like ?) and board0_.bno>0 order by board0_.bno desc
  ```

### Query의 장점

* 리턴값이 반드시 엔티티 타입이 아니라 필요한 몇 개의 칼럼만 추출할 수 있다.
* nativeQuery 속성을 지정해서 데이터베이스에 사용하는 SQL을 그대로 사용할 수 있다.
* Repository에 지정된 엔티티 타입뿐아니라 필요한 엔티티 타입을 다양하게 사용할 수 있다.

### Query Cost 란?

Query가 실행되는 데 걸리는 예상 수행시간

## @Param 사용법

```
@Query("SELECT b FROM Board b where b.content like %:content% AND b.bno>0 order by b.bno desc")
    public List<Board> findByContent(@Param("content") String content);
```

```
@Test
    public void testByContent2() {
        repo.findByContent("18").forEach(board->System.out.println(board));
    }
```

## 필요한 칼럼만 추출하는 경우

특정 칼럼만 가져오고 싶다면 아래와 같은 방식으로 작성하면 된다.

```
@Query("select b.bno, b.title, b.writer, b.regdate"+" from Board b WHERE b.title like %?1% and b.bno>0 order by b.bno desc")
    public List<Object[]> findByTitle2(String title);
```

```
@Test
    public void testBytitle17() {
        repo.findByTitle2("17").forEach(arr->System.out.println(Arrays.toString(arr)));
    }
```

## @Query 와 Paging 처리/정렬

```
    @Query("select b from Board b WHERE b.bno > 0 order by b.bno desc")
    public List<Board> findByPage(Pageable pageable);
```

```
    @Test
    public void testByPaging() {
         Pageable pageable = PageRequest.of(0, 10);

         repo.findByPage(pageable).forEach(board->System.out.println(board));
    }
```

## @Query를 이용할 때 주의할 점

@Query에 대한 해석은 프로젝트 로딩 시점에서 이루어진다. 따라서 @Query의 내용은 프로젝트가 시작되면서 검증되기 때문에 만일 @Query의 내용물이 잘못될 경우에는 프로젝트가 정상적으로 실행되지 않는다.

* 권고 : @Query를 하나씩 작성하고, 프로젝트를 실행하는 과정을 거치는 것이 좋다.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://djunnni.gitbook.io/springboot/2019-09-05.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
