![[JPA] Query Methods](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbO53eB%2FbtsJxXfjvQF%2FjGKZCA0jH98GYHw7R8QKk0%2Fimg.png)
[JPA] Query MethodsProgramming/SpringBoot2024. 9. 11. 21:04
Table of Contents
Query Methods란?
Spring Data JPA에서는 메서드 이름으로 SQL을 생성할 수 있는 Query Methods 기능을 제공한다.
JpaRepository 인터페이스에서 해당 인터페이스와 매핑되어있는 테이블에 요청하고자하는 SQL을 메서드 이름을 사용하여 선언할 수 있다.
MemoRepository 예시
import com.sparta.memo.entity.Memo;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface MemoRepository extends JpaRepository<Memo, Long> {
List<Memo> findAllByOrderByModifiedAtDesc();
}
- SimpleJpaRepository 클래스가 생성될 때 위처럼 직접 선언한 JpaRepository 인터페이스의 모든 메서드를 자동으로 구현해준다.
- JpaRepository 인터페이스의 메서드 즉, Query Methods는 개발자가 이미 정의 되어있는 규칙에 맞게 메서드를 선언하면 해당 메서드 이름을 분석하여 SimpleJpaRepository에서 구현이 된다.
- 따라서 우리는 인터페이스에 필요한 SQL에 해당하는 메서드 이름 패턴으로 메서드를 선언 하기만 하면 따로 구현하지 않아도 사용할 수 있다.
- findAllByOrderByModifiedAtDesc 해당 메서드 이름은 Memo 테이블에서 ModifiedAt
즉, 수정 시간을 기준으로 전체 데이터를 내림차순으로 가져오는 SQL을 실행하는 메서드를 생성할 수 있다.
- List<Memo> findAllByUsername(String username);
- 이렇게 Query Method를 선언했을 경우 ByUsername 에 값을 전달해줘야하기 때문에 파라미터에 해당 값의 타입과 변수명을 선언해준다.
- 즉, Query Methods 는 메서드의 파라미터를 통해 SQL에 필요한 값을 동적으로 받아 처리할 수 있다.
메모장 프로젝트 Query Methods 적용
최신 메모가 가장 상단에 나올 수 있도록 수정
public List<MemoResponseDto> getMemos() {
// DB 조회
return memoRepository.findAllByOrderByModifiedAtDesc().stream().map(MemoResponseDto::new).toList();
}
📌 [실습] Query Methods 기능을 사용하여 내용(contents)에 특정 키워드가 포함된 메모를 조회하는 API를 구현
- Controller를 통해 keyword를 Query String 방식으로 전달받아 메모를 조회하는 API를 추가.
- http://localhost:8080/api/memos/contents?keyword=
- 메서드명은 getMemosByKeyword 입니다.
- MemoService에 getMemosByKeyword 기능을 수행하는 메서드를 구현.
- ‘Postman’을 사용해서 테스트.
- 정렬 방법은 수정 시간을 기준으로 내림차순을 적용.
MemoController.java
import com.sparta.memo.dto.MemoRequestDto;
import com.sparta.memo.dto.MemoResponseDto;
import com.sparta.memo.service.MemoService;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api")
public class MemoController {
private final MemoService memoService;
public MemoController(MemoService memoService) {
this.memoService = memoService;
}
@PostMapping("/memos")
public MemoResponseDto createMemo(@RequestBody MemoRequestDto requestDto) {
return memoService.createMemo(requestDto);
}
@GetMapping("/memos")
public List<MemoResponseDto> getMemos() {
return memoService.getMemos();
}
@GetMapping("/memos/contents")
public List<MemoResponseDto> getMemosByKeyword(String keyword) {
return memoService.getMemosByKeyword(keyword);
}
@PutMapping("/memos/{id}")
public Long updateMemo(@PathVariable Long id, @RequestBody MemoRequestDto requestDto) {
return memoService.updateMemo(id, requestDto);
}
@DeleteMapping("/memos/{id}")
public Long deleteMemo(@PathVariable Long id) {
return memoService.deleteMemo(id);
}
}
MemoRepository.java
import com.sparta.memo.entity.Memo;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface MemoRepository extends JpaRepository<Memo, Long> {
List<Memo> findAllByOrderByModifiedAtDesc();
List<Memo> findAllByContentsContainsOrderByModifiedAtDesc(String keyword);
}
MemoService.java
import com.sparta.memo.dto.MemoRequestDto;
import com.sparta.memo.dto.MemoResponseDto;
import com.sparta.memo.entity.Memo;
import com.sparta.memo.repository.MemoRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
public class MemoService {
private final MemoRepository memoRepository;
public MemoService(MemoRepository memoRepository) {
this.memoRepository = memoRepository;
}
public MemoResponseDto createMemo(MemoRequestDto requestDto) {
// RequestDto -> Entity
Memo memo = new Memo(requestDto);
// DB 저장
Memo saveMemo = memoRepository.save(memo);
// Entity -> ResponseDto
MemoResponseDto memoResponseDto = new MemoResponseDto(saveMemo);
return memoResponseDto;
}
public List<MemoResponseDto> getMemos() {
// DB 조회
return memoRepository.findAllByOrderByModifiedAtDesc().stream().map(MemoResponseDto::new).toList();
}
public List<MemoResponseDto> getMemosByKeyword(String keyword) {
return memoRepository.findAllByContentsContainsOrderByModifiedAtDesc(keyword).stream().map(MemoResponseDto::new).toList();
}
@Transactional
public Long updateMemo(Long id, MemoRequestDto requestDto) {
// 해당 메모가 DB에 존재하는지 확인
Memo memo = findMemo(id);
// memo 내용 수정
memo.update(requestDto);
return id;
}
public Long deleteMemo(Long id) {
// 해당 메모가 DB에 존재하는지 확인
Memo memo = findMemo(id);
// memo 삭제
memoRepository.delete(memo);
return id;
}
private Memo findMemo(Long id) {
return memoRepository.findById(id).orElseThrow(() ->
new IllegalArgumentException("선택한 메모는 존재하지 않습니다.")
);
}
}
참고
https://seongwon.dev/Spring-MVC/20220913-Query-Method%EB%9E%80/#233-and-or
[JPA] Spring Data JPA의 Query Method
1. Spring Data JPA에서 쿼리를 만드는 방법 이전 게시글에서 Spring Data JPA에 대해 알아보며 해당 모듈은 Data Access Layer의 구현을 최대한 개선하는 것을 목표로 만들어졌다고 하였다. 또한 Data JPA에서
seongwon.dev
'Programming > SpringBoot' 카테고리의 다른 글
[JPA] JPA Auditing (0) | 2024.09.11 |
---|
@킴준현 :: 차근차근 꾸준히
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!