
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