Skip to content

Commit fb5d9aa

Browse files
authored
Merge pull request #81 from 2u6in/main
[7주차/빈] 워크북 제출합니다
2 parents 3761eab + 2b931f4 commit fb5d9aa

1 file changed

Lines changed: 168 additions & 0 deletions

File tree

keyword/chapter07/keyword.md

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
- Page와 Slice
2+
3+
Spring Data JPA에서 페이징 구현을 위해 제공하는 두 가지 인터페이스가 바로 Page와 Slice
4+
5+
```java
6+
//MemberRepository
7+
8+
...
9+
10+
Page<Member> findPageBy(Pageable pageable);
11+
Slice<Member> findSliceBy(Pageable pageable);
12+
13+
...
14+
```
15+
16+
## Page
17+
18+
- PageSlice를 상속했기 때문에 현재 페이지의 데이터에 더해서 전체 데이터의 개수와 전체 페이지 수를 모두 알고 있다
19+
- 조회(SELECT) 쿼리 이후 전체 데이터 개수를 조회(SELECT COUNT)하는 쿼리가 한 번 더 실행
20+
- 전체 페이지 개수나 데이터 개수가 필요한 경우 유용 (게시판 형태)
21+
22+
## Slice
23+
24+
- 현재 페이지에 포함된 데이터 목록과 다음 페이지가 있는지 여부에 대한 정보만 제공
25+
- 조회 쿼리 한 번만 실행
26+
- 사용자가 요청한 데이터 개수(limit)보다 하나 더 많은 데이터를 요청해서 다음 데이터 존재의 여부를 판단
27+
- COUNT 실행되지 않음
28+
- COUNT 쿼리가 생략되므로 대용량 데이터 조회 시 성능 상 유리
29+
- 총 데이터 개수가 필요 없는 상황에서 유용 (무한 스크롤)
30+
31+
- Java stream API
32+
33+
## Java stream API
34+
35+
데이터의 묶음을 반복문 없이 함수형 프로그래밍 방식으로 간결하게 처리 가능하게 해준다
36+
37+
### 과정
38+
39+
```java
40+
List<String> words = Arrays.asList("show", "me", "the", "money", "money");
41+
42+
List<String> distinctWords =
43+
words.stream() // 1. Stream 생성
44+
.filter(word -> word.length() > 3) // 2. 중간연산
45+
.distinct() // 2. 중간연산
46+
.collect(Collectors.toList()); // 3. 최종연산
47+
```
48+
49+
1. 생성
50+
- 컬렉션이나 배열 등의 데이터를 스트림 객체로 만든다
51+
- .stream
52+
2. 중간 연산
53+
- 데이터를 조건에 맞게 걸러내거나 변형
54+
- 연산
55+
- .filter(조건) : 조건이 참인 것만 통과
56+
- .distinct() : 중복 요소 제거
57+
- .map(Function) : 데이터를 함수를 통해서 내가 원하는 다른 형태로 변환 추출
58+
- .limit(size) : 스트림의 맨 앞부터 size만큼만 가져오기
59+
- sorted(condition) : 조건에 맞게 데이터 정렬, 없으면 오름차순
60+
3. 최종 연산
61+
- 가공된 데이터를 최종적인 결과물로 변환
62+
- 연산
63+
- .collect(.toList) : 스트림을 통과하며 가공된 데이터들을 List, Set, Map 같은 컬렉션 형태로 다시 포장
64+
- .count() : 최종 결과물에 데이터가 몇 개 남아있는지를 계산, long 리턴
65+
- .forEach(작업) : 스트림을 통과한 데이터들을 차례대로 하나씩 꺼내서 특정 작업을 실행, 변수에 담아서 반환X
66+
67+
### 특징
68+
69+
- 반복문을 사용하지 않고, 선언적으로 데이터 흐름을 표현
70+
- 중간 연산은 최종 연산이 호출되기 전까지 실제로 실행되지 않아 성능을 향상
71+
- 원본을 바꾸지 않음
72+
- 객체 그래프 탐색
73+
74+
## 객체 그래프 탐색
75+
76+
객체들이 서로 참조(Reference)를 통해 연결되어 있는데, 이 연결된 것이 그래프 같다고 해서 객체 그래프라고 함
77+
78+
그리고 이 객체 그래프를 따라가면서 찾는 것이 **객체 그래프 탐색**
79+
80+
```java
81+
String univName = menu.getCafeteria().getUniversity().getName();
82+
```
83+
84+
### JPA에서 왜 중요함?
85+
86+
RDB에서는 객체처럼 다른 테이블의 데이터를 마음대로 가지고 올 수 없고 JOIN 해야함따라서 SQL을 어떻게 짰느냐에 따라 자바 코드에서 객체를 탐색할 수 있는 범위가 한정됨
87+
88+
**JPA가 지연 로딩을 통해 해결!!**
89+
90+
```java
91+
// 1. DB에서 메뉴 번호 1번을 가져옴 (메뉴 테이블만 SELECT)
92+
Menu menu = menuRepository.findById(1L).orElseThrow();
93+
94+
// 2. 이때 식당(Cafeteria) 객체는 진짜 객체가 아니라 '가짜(프록시) 객체'가 들어있음
95+
Cafeteria cafeteria = menu.getCafeteria();
96+
97+
// 3. 실제로 식당의 이름이 필요한 순간
98+
// JPA가 몰래 DB에 SELECT 쿼리를 날려서 식당 데이터를 가져옴 (지연 로딩)
99+
System.out.println(cafeteria.getName());
100+
```
101+
102+
- 이 때 반복문으로 인한 N+1 문제를 조심해야함
103+
- fetch join!!
104+
- @Valid vs @Validated
105+
106+
## @Valid
107+
108+
- java에서 제공
109+
- 주로 밑 예시처럼 Controller에서 유효성 검증이 필요한 파라미터에 붙여서 사용
110+
111+
```java
112+
@PostMapping("/users")
113+
public ResponseEntity<?> createUser(@Valid @RequestBody UserDto userDto) {
114+
// userDto 내부의 @NotBlank, @NotNull 등이 검증됨
115+
return ResponseEntity.ok().build();
116+
}
117+
```
118+
119+
## @Validated
120+
121+
- spring 제공
122+
- 계층과 무관하게 Spring Bean이라면 유효성 검증을 진행
123+
- valid 기능을 모두 제공하면서 추가 기능 제공
124+
- 그룹 검증 지원
125+
- 같은 DTO 객체라도 로직(생성, 수정 등)에 따라 검증 조건이 다를 때 사용
126+
127+
```java
128+
// 1. 마커 인터페이스(그룹) 생성
129+
public interface CreateGroup {}
130+
public interface UpdateGroup {}
131+
132+
public class UserDto {
133+
@NotNull(groups = {UpdateGroup.class}) // 수정할 때만 필수
134+
private Long id;
135+
136+
@NotBlank(groups = {CreateGroup.class, UpdateGroup.class}) // 생성, 수정 모두 필수
137+
private String name;
138+
}
139+
140+
// 2. 컨트롤러에서 사용할 그룹 지정
141+
@PostMapping("/users")
142+
public ResponseEntity<?> createUser(@Validated(CreateGroup.class) @RequestBody UserDto dto) {
143+
// id 필드는 검증하지 않고, name 필드만 검증함
144+
return ResponseEntity.ok().build();
145+
}
146+
```
147+
148+
- 컨트롤러 클래스 파라미터 단일 검증
149+
- dto가 아닌 @RequestParam, @PathVariable 검증 시 사용
150+
- 클래스 위에 @Validated 선언
151+
152+
```java
153+
@RestController
154+
**@Validated // 컨트롤러 클래스 상단**
155+
@RequestMapping("/users")
156+
public class UserController {
157+
158+
@GetMapping("/{id}")
159+
public ResponseEntity<?> getUser(
160+
@PathVariable **@Min(1)** Long id // id가 1 이상인지 단일 검증
161+
) {
162+
return ResponseEntity.ok().build();
163+
}
164+
}
165+
```
166+
167+
168+
→ 일반적인 dto 검증은 @Valid 권장

0 commit comments

Comments
 (0)