스프링 | JPA

Salt·2023년 7월 15일

blog에 유저가 추가 될 때마다, blog_user 테이블과 user 테이블 두개를 만든다. (동적테이블)

유저 조회할 때마다, SELECT * FROM 으로 바로 불러올 수 있어서 로딩 속도가 빠르고 성능이 좋아진다. 근데 동적테이블은 JPA에서 일일이 테이블명을 못바꾼다. (Mybatis에서만 가능)

블로그에 추가할 기능 : 페이징(로딩속도개선, 최신글위주조회), 회원가입, 레디스(pending)

JPA

JPA 사용 이유 : 패러다임 불일치 라고 불리는 SQL과 자바의 언어 및 개념 불일치로 인해 야기되는 객체지향적 코드를 짜는데 어려움을 겪게되는 부분을 해소하기 위해 사용됩니다.


JPA 세팅

10장 - JPA 기초 및 단순 활용

uuid : auto_increment 를 안쓰고 uuid를 쓰는 이유는 DB 마이그레이션 문제(DB합치는거)로

인한 PK 동기화시 중복 오류를 해결함, uuid는 고유성을 보장하는 ID를 만들기 위한 표준 규약임

즉, 합쳤을 때 중복값이 없는 PK로 정렬됨


코드수정 (실수함ㅠ)

<div class="container">
        <**form action="/blog/update"** method="POST">

update할 때 목적지를 Controller의 update로 제대로 잡아주자..

Controller 첫번째꺼로 목적지를 잡아주고 있어서 수정버튼 눌러도 계속 무한으로 돌아가는게

반복되고 있었다 ;;;;;;

포스팅의 댓글들처럼, 회원의 구매목록들같은 일대다 관계에서는
외래키 설정을 해줘야 함!!!!!! (조인해야해서)


JPA 메서드 선언

public User findByEmail(String email);

특정한 키워드가 존재하는 게시글들을 갖고오기 (검색같은거에 활용할 수 있음)

Id값이 아닌 email 필드를 이용해 특정 개체를 찾아낸다.


페이징

페이징 같은 경우도 마이바티스에서는 코드 구현이 어렵지만, JPA에서는 Pageabe이라는 타입의

객체를 구성해서 파라미터로 넘기기만 하면 바로 적용된다.

조회조건을 세팅하는 예시코드

// 10개를 한 페이지로 지정해서, 0번째(첫) 페이지. 조회시 bno를 기준으로 역순 정렬
Pageable pageable = PageRequest.of(0, 10, Sort.by("bno").descending());

이제 위에서 만든 코드를 레포지토리명.findAll(pageable) 형식으로 처리

Page<엔터티자료형> result = 레포지토리명.findAll(pageable);

블로그에 적용해보자

Page<Blog> findAll(Pageable pageable);

먼저, 페이징 정보를 받는 findAll()메서드를 오버로딩 해줘야 함

pageable(페이지네이션정보를제공하는객체) 받아서, Page객체(정보)를 리턴한다.

@RequestMapping({"/list/{pageNum}", "/list"})

public String list(@PathVariable(required = false) Long pageNum, Model model) {
		Page<Blog> pageInfo = blogService.findAll(pageNum);

		// 한 페이지에 보여야 하는 페이징 버튼 그룹의 개수
		final int PAGE_BTN_NUM = 10;
		// 현재 조회중인 페이지번호
		int currentPageNum = pageInfo.getNumber() + 1;
		// 현재 조회중인 페이지 그룹의 끝번호
		int endPageNum = (int)Math.ceil(currentPageNum / (double)PAGE_BTN_NUM) * PAGE_BTN_NUM;
		// 현재 조회중인 페이지 그룹의 시작번호
		int startPageNum = endPageNum - PAGE_BTN_NUM + 1;
		// 마지막 그룹 번호 보정
		endPageNum = endPageNum > pageInfo.getTotalPages() ? pageInfo.getTotalPages() : endPageNum;
		// 이전페이지 버튼 (시작번호가 1이 아닐때)
		boolean prevBtn = startPageNum != 1;

		model.addAttribute("currentPageNum", currentPageNum);
		model.addAttribute("endPageNum", endPageNum);
		model.addAttribute("startPageNum", startPageNum);
		model.addAttribute("pageInfo", pageInfo);

		
		return "blog/list";	

}
Page<Blog> findAll(long pageNum);

서비스단에서는, 컨트롤러에서 건네받은 pageNum을 가지고 리턴해줘야함

@Override
public Page<Blog> findAll(Long pageNum) {

		Pageable pageable = PageRequest.of(getCalibratedPageNum(pageNum)-1, 10);
		return blogJPARepository.findAll(pageable);

}

구현체에서는, 컨트롤러에서 전달받은 pageNum → getCalibratedPageNum함수실행 →

페이지번호, 길이(한페이지에보여질페이지수)를 인자로 줘서 블로그게시글들 반환함


+대형 서비스에서 FK를 안거는 이유

 void deleteAllById(long blogId);

외래키는 자식이 부모꺼에 insert 전에 그 부모가 존재하는지 한 번 더 체크하는 장치인데, 이걸 걸면 DB쪽에서 트래픽이 너무 많이 발생한다. 그래서 외래키를 걸지 않으면서, 없는 글에 댓글이 달리게 할 수는 없으니 글이 있는지 확인한 다음 댓글을 확인하는 로직으로 짠다.

0개의 댓글