1. find로 한 건 조회하기
- 캐싱을 사용하여 데이터베이스 쿼리를 최적화하는 것
- 요청에 대한 응답을 캐시
후에 동일한 요청이 발생할 때 다시 데이터베이스에 액세스하지 않고 캐시된 결과를 반환
- 1번의 PK를 가진 보드 객체를 조회
- 있을 경우
이 경우 캐싱을 사용하여 해당 객체를 메모리에 저장
이후에 다시 동일한 PK를 가진 객체를 요청할 때는 바로 캐시된 객체를 반환
- 없을 경우
캐시에서 요청된 객체를 찾지 못한 경우에 대한 실패를 캐시 시스템이 확인
데이터베이스에 대한 조회 쿼리가 생성 / 캐싱된 객체를 찾을 수 없는 경우에만 실
요청된 PK를 기반으로 데이터베이스의 특정 테이블에서 객체를 검색하는 SELECT 쿼리
데이터베이스에서 객체를 검색한 후에는 검색된 객체를 메모리에 로드하여 응답을 생성
조회된 객체는 캐시에 저장하기 전에 즉시반환
객체가 캐시에 저장되어야 할 경우, 데이터베이스로부터 가져온 객체가 캐시에 저장
이후 동일한 요청이 발생할 때는 캐시된 객체 사용 가능
조회된 객체를 클라이언트에게 응답으로 전달
- 주의할 점 : 항상 최신 상태인지 확인, 데이터가 변경될 때 적절하게 캐시를 갱신이 필요
- 요청이 올 때 객체 생성과 초기화
요청이 오면 새로운 보드 객체를 생성
일반적으로 기본 생성자를 호출하여 객체를 생성
새로 생성된 보드 객체는 초기화 단계를 거침 / 필요한 속성들을 설정하고 객체를 준비하는 단계
- 응답을 받은 경우 객체의 상태 변화:
이 응답에 포함된 보드 객체를 영속화 : 객체를 메모리에 저장하고 캐시에 넣어둠
이후 동일한 요청이 오면 캐시에서 해당 객체를 찾을 수 있음
다시 객체를 생성할 필요 없이 캐시된 객체를 사용하여 응답을 바로 반환
2. BoardPersistRepository 에 findById() 만들기
- 한 건을 찾을 땐 find 사용하기
package shop.mtcoding.blog.board; import jakarta.persistence.EntityManager; import jakarta.persistence.Query; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; import java.util.List; @RequiredArgsConstructor @Repository public class BoardPersistRepository { private final EntityManager em; public Board findById(Integer id) { Board board = em.find(Board.class, id); // (class명, PK) return board; } public List<Board> findAll() { Query query = em.createQuery("select b from Board b order by b.id desc", Board.class); return query.getResultList(); } @Transactional public Board save(Board board) { // PC에 Data 주소 넣기(Entity만 가능함) em.persist(board); // 실행후 영속 객체가 됨 return board; } }
- 단위 테스트 하기
package shop.mtcoding.blog.Board; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.context.annotation.Import; import shop.mtcoding.blog.board.Board; import shop.mtcoding.blog.board.BoardPersistRepository; import java.util.List; @Import(BoardPersistRepository.class) @DataJpaTest public class BoardPersistRepositoryTest { @Autowired //DI private BoardPersistRepository boardPersistRepository; @Test public void findById_test() { //given int id = 1; //when Board board = boardPersistRepository.findById(id); System.out.println("findById_test : " + board); //then //org.assertj.core.api Assertions.assertThat(board.getTitle()).isEqualTo("제목1"); Assertions.assertThat(board.getContent()).isEqualTo("내용1"); } @Test public void findAll_test() { //given - 지금은 넣을게 없음 //when List<Board> boardList = boardPersistRepository.findAll(); //then System.out.println("findAll_test/size : " + boardList.size()); System.out.println("findAll_test/username : " + boardList.get(2).getUsername()); //org.assertj.core.api Assertions.assertThat(boardList.size()).isEqualTo(4); Assertions.assertThat(boardList.get(2).getUsername()).isEqualTo("ssar"); } @Test public void save_test() { //given Board board = new Board("제목5","내용5","ssar"); //when boardPersistRepository.save(board); //then System.out.println(board); } }
- 1개의 id 두 번 전송 → 1개만 적용
@Test public void findById_test() { //given int id = 1; //when Board board = boardPersistRepository.findById(id); boardPersistRepository.findById(id); System.out.println("findById_test : " + board); }
- 두 개의 id가 다른 경우 → 다 실행
@Test public void findById_test() { //given int id1 = 1; int id2 = 2; //when Board board1 = boardPersistRepository.findById(id1); Board board2 = boardPersistRepository.findById(id2); System.out.println("findById_test : " + board1); System.out.println("findById_test : " + board2); }
3. BoardController 에 detail 수정하
package shop.mtcoding.blog.board; import ch.qos.logback.core.model.Model; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import java.lang.annotation.Native; import java.util.List; @RequiredArgsConstructor @Controller public class BoardController { private final BoardNativeRepository boardNativeRepository; private final BoardPersistRepository boardPersistRepository; @PostMapping("/board/{id}/update") public String update(@PathVariable Integer id, String title, String content, String username){ boardNativeRepository.updateById(id, title, content, username); return "redirect:/board/"+id; } @GetMapping("/board/{id}/update-form") public String updateForm(@PathVariable (name="id") Integer id, HttpServletRequest request) { Board board = boardNativeRepository.findById(id); request.setAttribute("board", board); return "/board/update-form"; // 서버가 내부적으로 index를 요청 - 외부에서는 다이렉트 접근이 안됨 } @PostMapping("/board/{id}/delete") public String delete(@PathVariable Integer id) { // DTO 없이 구현 boardNativeRepository.deleteById(id); return "redirect:/"; } @GetMapping("/") public String index(HttpServletRequest request) { // 조회하기 List<Board> boardList = boardPersistRepository.findAll(); // 가방에 담기 request.setAttribute("boardList", boardList); return "index"; // 서버가 내부적으로 index를 요청 - 외부에서는 다이렉트 접근이 안됨 } @PostMapping("/board/save") public String save(BoardRequest.SaveDTO reqDTO) { // DTO 없이 구현 boardPersistRepository.save(reqDTO.toEntity()); return "redirect:/"; } @GetMapping("/board/save-form") public String saveForm() { return "board/save-form"; } @GetMapping("/board/{id}") public String detail(@PathVariable Integer id, HttpServletRequest request) { // Integer : 없으면 null, int : 0 Board board = boardPersistRepository.findById(id); request.setAttribute("board", board); return "board/detail"; } }
Share article