[Spring Data JPA] - ์ˆœ์ˆ˜ JPA ๐Ÿ‘‰ Spring Data JPA ํŽ˜์ด์ง•, ์ •๋ ฌ

ํ™์ •์™„ยท2022๋…„ 7์›” 13์ผ
0

JPA

๋ชฉ๋ก ๋ณด๊ธฐ
18/38
post-thumbnail

์ˆœ์ˆ˜ JPA ํŽ˜์ด์ง•๊ณผ ์ •๋ ฌ


  • ๊ฒ€์ƒ‰ ์กฐ๊ฑด : ๋‚˜์ด 10์‚ด

  • ์ •๋ ฌ ์กฐ๊ฑด : ์ด๋ฆ„์œผ๋กœ ๋‚ด๋ฆผ์ฐจ์ˆœ

  • ํŽ˜์ด์ง• ์กฐ๊ฑด : ์ฒซ ๋ฒˆ์งธ ํŽ˜์ด์ง€, ํŽ˜์ด์ง€๋‹น ๋ณด์—ฌ์ค„ ๋ฐ์ดํ„ฐ๋Š” 3๊ฑด



  • ์œ„ ์กฐ๊ฑด์œผ๋กœ ์ˆœ์ˆ˜ JPA์˜ ํŽ˜์ด์ง•๊ณผ ์ •๋ ฌ์„ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ์ œ ์ฝ”๋“œ๋ฅผ ๋ณด์ž.



// ์ˆœ์ˆ˜ JPA ํŽ˜์ด์ง• Repository ์ฝ”๋“œ

public List<Member> findByPage(int age, int offset, int limit) {
 	return em.createQuery("select m from Member m where m.age = :age order by m.username desc")
 				.setParameter("age", age)
 				.setFirstResult(offset)
 				.setMaxResults(limit)
 				.getResultList();
}


public long totalCount(int age) {
 	return em.createQuery("select count(m) from Member m where m.age = :age", Long.class)
 				.setParameter("age", age)
 				.getSingleResult();
}



// ์ˆœ์ˆ˜ JPA ํŽ˜์ด์ง• test ์ฝ”๋“œ

@Test
public void paging() throws Exception {

 	//given
	memberJpaRepository.save(new Member("member1", 10));
	memberJpaRepository.save(new Member("member2", 10));
	memberJpaRepository.save(new Member("member3", 10));
	memberJpaRepository.save(new Member("member4", 10));
	memberJpaRepository.save(new Member("member5", 10));
 
	int age = 10;
 	int offset = 0;
	int limit = 3;
 
 
	//when
	List<Member> members = memberJpaRepository.findByPage(age, offset, limit);
	long totalCount = memberJpaRepository.totalCount(age);
 
 
 	//then
	assertThat(members.size()).isEqualTo(3);
	assertThat(totalCount).isEqualTo(5);
}



Spring Data JPA ํŽ˜์ด์ง•๊ณผ ์ •๋ ฌ


ํŽ˜์ด์ง•๊ณผ ์ •๋ ฌ ํŒŒ๋ผ๋ฏธํ„ฐ

  • org.springframework.data.domain.Sort : ์ •๋ ฌ ๊ธฐ๋Šฅ

  • org.springframework.data.domain.Pageable : ํŽ˜์ด์ง• ๊ธฐ๋Šฅ (๋‚ด๋ถ€์— Sort ํฌํ•จ)


ํŠน๋ณ„ํ•œ ๋ฐ˜ํ™˜ ํƒ€์ž…

  • org.springframework.data.domain.Page : ์ถ”๊ฐ€ count ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ํฌํ•จํ•˜๋Š” ํŽ˜์ด์ง•

  • org.springframework.data.domain.Slice : ์ถ”๊ฐ€ count ์ฟผ๋ฆฌ ์—†์ด ๋‹ค์Œ ํŽ˜์ด์ง€๋งŒ ํ™•์ธ ๊ฐ€๋Šฅ

    • (๋‚ด๋ถ€์ ์œผ๋กœ limit + 1์กฐํšŒ)
  • List (์ž๋ฐ” ์ปฌ๋ ‰์…˜) : ์ถ”๊ฐ€ count ์ฟผ๋ฆฌ ์—†์ด ๊ฒฐ๊ณผ๋งŒ ๋ฐ˜ํ™˜



// ํŽ˜์ด์ง•๊ณผ ์ •๋ ฌ ์‚ฌ์šฉ ์˜ˆ์ œ

Page<Member> findByUsername(String name, Pageable pageable); // count ์ฟผ๋ฆฌ ์‚ฌ์šฉ

Slice<Member> findByUsername(String name, Pageable pageable); // count ์ฟผ๋ฆฌ ์‚ฌ์šฉ ์•ˆํ•จ

List<Member> findByUsername(String name, Pageable pageable); // count ์ฟผ๋ฆฌ ์‚ฌ์šฉ ์•ˆํ•จ

List<Member> findByUsername(String name, Sort sort);



  • ๊ฒ€์ƒ‰ ์กฐ๊ฑด : ๋‚˜์ด 10์‚ด

  • ์ •๋ ฌ ์กฐ๊ฑด : ์ด๋ฆ„์œผ๋กœ ๋‚ด๋ฆผ์ฐจ์ˆœ

  • ํŽ˜์ด์ง• ์กฐ๊ฑด : ์ฒซ ๋ฒˆ์งธ ํŽ˜์ด์ง€, ํŽ˜์ด์ง€๋‹น ๋ณด์—ฌ์ค„ ๋ฐ์ดํ„ฐ๋Š” 3๊ฑด



  • ์œ„ ์กฐ๊ฑด์œผ๋กœ Spring Data JPA์˜ ํŽ˜์ด์ง•๊ณผ ์ •๋ ฌ์„ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ์ œ ์ฝ”๋“œ๋ฅผ ๋ณด์ž.



// Page ์‚ฌ์šฉ ์˜ˆ์ œ ์ •์˜ ์ฝ”๋“œ

public interface MemberRepository extends Repository<Member, Long> {

 	Page<Member> findByAge(int age, Pageable pageable);
}

  • ๋‘ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์€ Pagable์€ ์ธํ„ฐํŽ˜์ด์Šค

  • ๋”ฐ๋ผ์„œ ์‹ค์ œ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ํ•ด๋‹น ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ org.springframework.data.domain.PageRequest ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉ



// Page ์‚ฌ์šฉ ์˜ˆ์ œ ์‹คํ–‰ ์ฝ”๋“œ

// ํŽ˜์ด์ง• ์กฐ๊ฑด๊ณผ ์ •๋ ฌ ์กฐ๊ฑด ์„ค์ •
@Test
public void page() throws Exception {

 	//given
	memberRepository.save(new Member("member1", 10));
 	memberRepository.save(new Member("member2", 10));
 	memberRepository.save(new Member("member3", 10));
 	memberRepository.save(new Member("member4", 10));
	memberRepository.save(new Member("member5", 10));
 
 
 	//when
 	PageRequest pageRequest = PageRequest.of(0, 3, Sort.by(Sort.Direction.DESC, "username"));
 	Page<Member> page = memberRepository.findByAge(10, pageRequest);
 
 
 	//then
 	List<Member> content = page.getContent(); 		   // ์กฐํšŒ๋œ ๋ฐ์ดํ„ฐ
 	assertThat(content.size()).isEqualTo(3); 		   // ์กฐํšŒ๋œ ๋ฐ์ดํ„ฐ ์ˆ˜
 	assertThat(page.getTotalElements()).isEqualTo(5);  // ์ „์ฒด ๋ฐ์ดํ„ฐ ์ˆ˜
 	assertThat(page.getNumber()).isEqualTo(0); 		   // ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ
 	assertThat(page.getTotalPages()).isEqualTo(2); 	   // ์ „์ฒด ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ
 	assertThat(page.isFirst()).isTrue(); 			   // ์ฒซ๋ฒˆ์งธ ํ•ญ๋ชฉ์ธ๊ฐ€?
 	assertThat(page.hasNext()).isTrue(); 			   // ๋‹ค์Œ ํŽ˜์ด์ง€๊ฐ€ ์žˆ๋Š”๊ฐ€?
}

  • PageRequest ์ƒ์„ฑ์ž์˜ ์ฒซ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ์—๋Š” ํ˜„์žฌ ํŽ˜์ด์ง€๋ฅผ, ๋‘ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ์—๋Š” ์กฐํšŒํ•  ๋ฐ์ดํ„ฐ ์ˆ˜๋ฅผ ์ž…๋ ฅ

  • ์—ฌ๊ธฐ์— ์ถ”๊ฐ€๋กœ ์ •๋ ฌ ์ •๋ณด๋„ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.


โœ… Page๋Š” 1๋ถ€ํ„ฐ ์‹œ์ž‘์ด ์•„๋‹ˆ๋ผ 0๋ถ€ํ„ฐ ์‹œ์ž‘




// Page ์ธํ„ฐํŽ˜์ด์Šค

public interface Page<T> extends Slice<T> {

 	int getTotalPages(); 	 // ์ „์ฒด ํŽ˜์ด์ง€ ์ˆ˜
 	long getTotalElements(); // ์ „์ฒด ๋ฐ์ดํ„ฐ ์ˆ˜
 	<U> Page<U> map(Function<? super T, ? extends U> converter); // ๋ณ€ํ™˜๊ธฐ
}

// Slice ์ธํ„ฐํŽ˜์ด์Šค

public interface Slice<T> extends Streamable<T> {

	int getNumber(); 			// ํ˜„์žฌ ํŽ˜์ด์ง€
	int getSize(); 				// ํŽ˜์ด์ง€ ํฌ๊ธฐ
	int getNumberOfElements();  // ํ˜„์žฌ ํŽ˜์ด์ง€์— ๋‚˜์˜ฌ ๋ฐ์ดํ„ฐ ์ˆ˜
	List<T> getContent(); 		// ์กฐํšŒ๋œ ๋ฐ์ดํ„ฐ
	boolean hasContent(); 		// ์กฐํšŒ๋œ ๋ฐ์ดํ„ฐ ์กด์žฌ ์—ฌ๋ถ€
	Sort getSort(); 			// ์ •๋ ฌ ์ •๋ณด
	boolean isFirst(); 			// ํ˜„์žฌ ํŽ˜์ด์ง€๊ฐ€ ์ฒซ ํŽ˜์ด์ง€ ์ธ์ง€ ์—ฌ๋ถ€
	boolean isLast(); 			// ํ˜„์žฌ ํŽ˜์ด์ง€๊ฐ€ ๋งˆ์ง€๋ง‰ ํŽ˜์ด์ง€ ์ธ์ง€ ์—ฌ๋ถ€
	boolean hasNext(); 			// ๋‹ค์Œ ํŽ˜์ด์ง€ ์—ฌ๋ถ€
	boolean hasPrevious(); 		// ์ด์ „ ํŽ˜์ด์ง€ ์—ฌ๋ถ€
	Pageable getPageable(); 	// ํŽ˜์ด์ง€ ์š”์ฒญ ์ •๋ณด
	Pageable nextPageable(); 	// ๋‹ค์Œ ํŽ˜์ด์ง€ ๊ฐ์ฒด
	Pageable previousPageable();// ์ด์ „ ํŽ˜์ด์ง€ ๊ฐ์ฒด
	<U> Slice<U> map(Function<? super T, ? extends U> converter); // ๋ณ€ํ™˜๊ธฐ
}



count ์ฟผ๋ฆฌ ๋ถ„๋ฆฌ


//  count ์ฟผ๋ฆฌ๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ถ„๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

@Query(value = โ€œselect m from Member mโ€, countQuery = โ€œselect count(m.username) from Member mโ€)
Page<Member> findMemberAllCountBy(Pageable pageable);

  • ์นด์šดํŠธ ์ฟผ๋ฆฌ ๋ถ„๋ฆฌ (๋ณต์žกํ•œ sql์—์„œ ์‚ฌ์šฉ, ๋ฐ์ดํ„ฐ๋Š” left join, ์นด์šดํŠธ๋Š” left join ์•ˆ ํ•ด๋„ ๋จ)

    • ์‹ค๋ฌด์—์„œ ๋งค์šฐ ์ค‘์š”

โœ… ์ „์ฒด count ์ฟผ๋ฆฌ๋Š” ๋งค์šฐ ๋ฌด๊ฒ๋‹ค.


ํŽ˜์ด์ง€๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ ์—”ํ‹ฐํ‹ฐ๋ฅผ DTO๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ


Page<Member> page = memberRepository.findByAge(10, pageRequest);
Page<MemberDto> dtoPage = page.map(m -> new MemberDto());
profile
์Šต๊ด€์ด ์ „๋ถ€๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€