[์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA] 4. ์ฟผ๋ฆฌ ๋ฉ”์†Œ๋“œ ๊ธฐ๋Šฅ

2022. 9. 28. 10:35ใ†์ธํ”„๋Ÿฐ/์‹ค์ „! ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA

728x90

 

0๏ธโƒฃ ์ฟผ๋ฆฌ ๋ฉ”์†Œ๋“œ ๊ธฐ๋Šฅ 

- ๋ฉ”์†Œ๋“œ ์ด๋ฆ„์œผ๋กœ ์ฟผ๋ฆฌ ์ƒ์„ฑ 
- NamedQuery
- @Query : ๋ฆฌํŒŒ์ง€ํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ์— ์ฟผ๋ฆฌ ์ •์˜ 
- ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉ
- ๋ฐ˜ํ™˜ ํƒ€์ž…
- ํŽ˜์ด์ง•๊ณผ ์ •๋ ฌ 
- ๋ฒŒํฌ์„ฑ ์ˆ˜์ • ์ฟผ๋ฆฌ 
- @EntityGraph 

-> ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA๊ฐ€ ์ถ”๊ฐ€๋กœ ๋” ํŽธํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๋„๋ก ์ œ๊ณตํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ๋“ค!! 

 

 

- ์ฟผ๋ฆฌ ๋ฉ”์†Œ๋“œ ๊ธฐ๋Šฅ 3๊ฐ€์ง€ 

- ๋ฉ”์†Œ๋“œ ์ด๋ฆ„์œผ๋กœ ์ฟผ๋ฆฌ ์ƒ์„ฑ
- ๋ฉ”์†Œ๋“œ ์ด๋ฆ„์œผ๋กœ JPA NamedQuery ํ˜ธ์ถœ 
- @Query ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•ด์„œ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ์ธํ„ฐํŽ˜์ด์Šค์— ์ฟผ๋ฆฌ ์ง์ ‘ ์ •์˜ 

 

 

1๏ธโƒฃ ๋ฉ”์†Œ๋“œ ์ด๋ฆ„์œผ๋กœ ์ฟผ๋ฆฌ ์ƒ์„ฑ

: ๋ฉ”์†Œ๋“œ ์ด๋ฆ„์„ ๋ถ„์„ํ•ด์„œ JPQL ์ฟผ๋ฆฌ ์‹คํ–‰ 

 

- ์ˆœ์ˆ˜ JPA ๋ฆฌํฌ์ง€ํ† ๋ฆฌ 

MemberJpaRepository

-> Member๊ฐ์ฒด์—์„œ ์ด๋ฆ„์ด ๊ฐ™๊ณ , ๋‚˜์ด๊ฐ€ ์ฃผ์–ด์ง„ ๋‚˜์ด๋ณด๋‹ค ๋งŽ์€ ํšŒ์› ์กฐํšŒํ•˜๋Š” ์ฟผ๋ฆฌ์ด๋‹ค. 

์ˆœ์ˆ˜ JPA ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์—์„œ๋Š” ๊ทธ๋ƒฅ ์กฐ๊ฑด์— ๋งž๊ฒŒ JPQL ์ฟผ๋ฆฌ๋ฅผ ์งฐ๋‹ค. 

 

 

MemberJpaRepositoryTest

jpql์€ sql๋กœ ๋ณ€ํ™˜๋˜์–ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ „์†กํ•œ๋‹ค. 

 

 

- ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA

MemberRepository

-> ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA์—์„œ๋Š” ์ˆœ์ˆ˜ JPA์™€๋Š” ๋‹ค๋ฅด๊ฒŒ ๊ทธ๋ƒฅ ๋ฉ”์†Œ๋“œ ์ด๋ฆ„์„ ๋ถ„์„ํ•ด์„œ JPQL์„ ์ƒ์„ฑํ•ด์„œ ์‹คํ–‰ํ•ด์ค€๋‹ค..!!!

(์™„์ „ ๋งˆ๋ฒ•๊ฐ™์Œ.. ์งฑ์‹ ๊ธฐ)

 

MemberRepositoryTest

์œ„์— MemberJpaRepositoryTest์™€ ๋™์ผํ•œ ํ…Œ์ŠคํŠธ์ธ๋ฐ ์ด๋ฒˆ์—๋Š” ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ jpa๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๊ฒฐ๊ณผ๋Š” ์œ„์—์„œ ํ–ˆ๋˜ ํ…Œ์ŠคํŠธ์™€ ๋™์ผํ•˜๋‹ค. 

 

 

 

์ฟผ๋ฆฌ ๋ฉ”์†Œ๋“œ ํ•„ํ„ฐ ์กฐ๊ฑด

Spring Data JPA - Reference Documentation

 

Spring Data JPA - Reference Documentation

Example 109. Using @Transactional at query methods @Transactional(readOnly = true) interface UserRepository extends JpaRepository { List findByLastname(String lastname); @Modifying @Transactional @Query("delete from User u where u.active = false") void del

docs.spring.io

 

Keyword              Sample                                                                  JPQL snippet

Distinct findDistinctByLastnameAndFirstname select distinct …โ€‹ where x.lastname = ?1 and x.firstname = ?2
And findByLastnameAndFirstname … where x.lastname = ?1 and x.firstname = ?2
Or findByLastnameOrFirstname … where x.lastname = ?1 or x.firstname = ?2
Is, Equals findByFirstname,findByFirstnameIs,findByFirstnameEquals … where x.firstname = ?1
Between findByStartDateBetween … where x.startDate between ?1 and ?2
LessThan findByAgeLessThan … where x.age < ?1
LessThanEqual findByAgeLessThanEqual … where x.age <= ?1
GreaterThan findByAgeGreaterThan … where x.age > ?1
GreaterThanEqual findByAgeGreaterThanEqual … where x.age >= ?1
After findByStartDateAfter … where x.startDate > ?1
Before findByStartDateBefore … where x.startDate < ?1
IsNull, Null findByAge(Is)Null … where x.age is null
IsNotNull, NotNull findByAge(Is)NotNull … where x.age not null
Like findByFirstnameLike … where x.firstname like ?1
NotLike findByFirstnameNotLike … where x.firstname not like ?1
StartingWith findByFirstnameStartingWith … where x.firstname like ?1 (parameter bound with appended %)
EndingWith findByFirstnameEndingWith … where x.firstname like ?1 (parameter bound with prepended %)
Containing findByFirstnameContaining … where x.firstname like ?1 (parameter bound wrapped in %)
OrderBy findByAgeOrderByLastnameDesc … where x.age = ?1 order by x.lastname desc
Not findByLastnameNot … where x.lastname <> ?1
In findByAgeIn(Collection<Age> ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection<Age> ages) … where x.age not in ?1
True findByActiveTrue() … where x.active = true
False findByActiveFalse() … where x.active = false
IgnoreCase findByFirstnameIgnoreCase … where UPPER(x.firstname) = UPPER(?1)

 

์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์ฟผ๋ฆฌ ๋ฉ”์†Œ๋“œ ๊ธฐ๋Šฅ

- ์กฐํšŒ: find...By, read...By, query..By, get...By 

Spring Data JPA - Reference Documentation

 

Spring Data JPA - Reference Documentation

Example 109. Using @Transactional at query methods @Transactional(readOnly = true) interface UserRepository extends JpaRepository { List findByLastname(String lastname); @Modifying @Transactional @Query("delete from User u where u.active = false") void del

docs.spring.io

interface PersonRepository extends Repository<Person, Long> {

  List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);

  // Enables the distinct flag for the query
  List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);
  List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname);

  // Enabling ignoring case for an individual property
  List<Person> findByLastnameIgnoreCase(String lastname);
  // Enabling ignoring case for all suitable properties
  List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname);

  // Enabling static ORDER BY for a query
  List<Person> findByLastnameOrderByFirstnameAsc(String lastname);
  List<Person> findByLastnameOrderByFirstnameDesc(String lastname);
}

์˜ˆ) findHelloBy ์ฒ˜๋Ÿผ ...์—๋Š” ์‹๋ณ„ํ•˜๊ธฐ ์œ„ํ•œ ๋‚ด์šฉ(์„ค๋ช…)์ด ๋“ค์–ด๊ฐ€๋„ ๋œ๋‹ค. 

 

COUNT: count...By ๋ฐ˜ํ™˜ํƒ€์ž… long

EXISTS: existst...By ๋ฐ˜ํ™˜ํƒ€์ž… boolean

์‚ญ์ œ: delete...By, remove...By ๋ฐ˜ํ™˜ํƒ€์ž… long 

DISTINCT: findDistinct, findMemberDistinctBy

LIMIT: findFirst3, findFirst, findTop, findTop3

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/ #repositories.limit-query-result

 

Spring Data JPA - Reference Documentation

Example 109. Using @Transactional at query methods @Transactional(readOnly = true) interface UserRepository extends JpaRepository { List findByLastname(String lastname); @Modifying @Transactional @Query("delete from User u where u.active = false") void del

docs.spring.io

User findFirstByOrderByLastnameAsc();

User findTopByOrderByAgeDesc();

Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);

Slice<User> findTop3ByLastname(String lastname, Pageable pageable);

List<User> findFirst10ByLastname(String lastname, Sort sort);

List<User> findTop10ByLastname(String lastname, Pageable pageable);

 

โ— ์ฐธ๊ณ 

์ด ๊ธฐ๋Šฅ์€ ์—”ํ‹ฐํ‹ฐ์˜ ํ•„๋“œ๋ช…์ด ๋ณ€๊ฒฝ๋˜๋ฉด ์ธํ„ฐํŽ˜์ด์Šค์— ์ •์˜ํ•œ ๋ฉ”์„œ๋“œ ์ด๋ฆ„๋„ ๊ผญ ํ•จ๊ป˜ ๋ณ€๊ฒฝํ•ด์•ผ ํ•œ๋‹ค!!

๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ํ•˜๋Š” ์‹œ์ ์— ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค!! 

์ด๋ ‡๊ฒŒ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ๋”ฉ ์‹œ์ ์— ์˜ค๋ฅ˜๋ฅผ ์ธ์ง€ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA์˜ ๋งค์šฐ ํฐ ์žฅ์ ์ด๋‹ค. 

 

 

2๏ธโƒฃ JPA NamedQuery

: Jpa์˜ NamedQuery๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Œ. 

 

Member

Member ๊ฐ์ฒด์— @NamedQuery ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ Naemd ์ฟผ๋ฆฌ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค. 

๊ทธ๋Ÿฌ๋ฉด ํ•ด๋‹น select m from Member ~ ์ฟผ๋ฆฌ์˜ ์ด๋ฆ„์€ Member.findByUsername์ด๋‹ค. 

 

 

- ์ˆœ์ˆ˜ JPA๋ฅผ ์‚ฌ์šฉํ•ด์„œ Named ์ฟผ๋ฆฌ ํ˜ธ์ถœ

MemberJpaRepository

์ด๋Ÿฐ์‹์œผ๋กœ createNamedQuery ๋ฉ”์†Œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์•„๊นŒ Member์— ์ง€์ •ํ–ˆ๋˜ NamedQeury ์ด๋ฆ„์„ ์„ค์ •ํ•ด์ค€๋‹ค. 

 

- ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA๋กœ NamedQuery ์‚ฌ์šฉ

MemberRepository

@Query(name = "Member.findByUsername") ์ด๊ฑธ ์ƒ๋žตํ•ด๋„ ๋™์ž‘ํ•œ๋‹ค!!

๊ทธ๋Ÿด ์ˆ˜ ์žˆ๋Š” ์ด์œ ๊ฐ€ ์šฐ์„  ํ•ด๋‹น ๋ฉ”์„œ๋“œ ์ด๋ฆ„์„ ๊ฐ€์ง€๊ณ  NamedQuery๋ฅผ Member๊ฐ์ฒด์—์„œ ์ฐพ๋Š”๋ฐ, 

๊ฐ™์€ ์ด๋ฆ„์ด ์กด์žฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— NamedQuery๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. 

๊ทผ๋ฐ ๋งŒ์•ฝ Member ๊ฐ์ฒด์— ๋™์ผํ•œ ๋ฉ”์„œ๋“œ ์ด๋ฆ„์„ ๊ฐ€์ง„ NamedQuery๊ฐ€ ์—†๋‹ค๋ฉด ๊ทธ๋•Œ ๋ฉ”์„œ๋“œ ์ด๋ฆ„์„ ๊ธฐ์ค€์œผ๋กœ ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค. 

 

โ— ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA๋Š” ์„ ์–ธํ•œ "๋„๋ฉ”์ธ ํด๋ž˜์Šค + .(์ ) + ๋ฉ”์„œ๋“œ ์ด๋ฆ„"์œผ๋กœ Named ์ฟผ๋ฆฌ๋ฅผ ์ฐพ์•„์„œ ์‹คํ–‰ 

๊ทธ๋ฆฌ๊ณ  ๋งŒ์•ฝ ์‹คํ–‰ํ•œ Named ์ฟผ๋ฆฌ๊ฐ€ ์—†์œผ๋ฉด ๋ฉ”์„œ๋“œ ์ด๋ฆ„์œผ๋กœ ์ฟผ๋ฆฌ ์ƒ์„ฑ ์ „๋žต์„ ์‚ฌ์šฉํ•œ๋‹ค. 

(ํ•„์š”ํ•˜๋ฉด ์ „๋žต์„ ๋ณ€๊ฒฝํ•  ์ˆ˜๋„ ์žˆ๋Š”๋ฐ ๊ตณ์ด ๊ถŒ์žฅํ•˜์ง€๋Š” ์•Š๋Š”๋‹ค๊ณ  ํ•œ๋‹ค.)

 

 

 

3๏ธโƒฃ @Query, ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ์— ์ฟผ๋ฆฌ ์ •์˜ํ•˜๊ธฐ 

MemberRepository

: ๋ฉ”์„œ๋“œ์— JPQL ์ฟผ๋ฆฌ ์ž‘์„ฑ 

@org.springframework.data.jpa.repository.Query ์–ด๋…ธํ…Œ์ด์…˜ ์‚ฌ์šฉ 

์‹คํ–‰ํ•  ๋ฉ”์„œ๋“œ์— ์ •์  ์ฟผ๋ฆฌ๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•˜๋ฏ€๋กœ ์ด๋ฆ„ ์—†๋Š” Named ์ฟผ๋ฆฌ๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค. 

JPA Named ์ฟผ๋ฆฌ์ฒ˜๋Ÿผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰ ์‹œ์ ์— ๋ฌธ๋ฒ• ์˜ค๋ฅ˜๋ฅผ ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ์Œ (์—„์ฒญ๋‚œ ์žฅ์ !!) 

-> ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ jpa๋Š” ๋จผ์ € ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰ ์‹œ์ ์— ์ฟผ๋ฆฌ๋“ค์„ ๋ชจ๋‘ ํŒŒ์‹ฑํ•ด์„œ sql๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์ž‘์—…์„ ํ•œ๋‹ค๊ณ  ํ•œ๋‹ค.

 ๊ทผ๋ฐ ํŒŒ์‹ฑํ•˜๋ฉด์„œ๋„ ์˜ค๋ฅ˜๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค!!! 

 

โ— ์ฐธ๊ณ 

์‹ค๋ฌด์—์„œ๋Š” ๋ฉ”์†Œ๋“œ ์ด๋ฆ„์œผ๋กœ ์ฟผ๋ฆฌ ์ƒ์„ฑ ๊ธฐ๋Šฅ์€ ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์ฆ๊ฐ€ํ•˜๋ฉด ๋ฉ”์„œ๋“œ ์ด๋ฆ„์ด ๋งค์šฐ ์ง€์ €๋ถ„ํ•ด์ง„๋‹ค...! (์กฐ๊ฑด์ด ๋งŽ์•„์ง€๋ฉด ๋ฉ”์†Œ๋“œ ์ด๋ฆ„์ด ๋„ˆ๋ฌด ๊ธธ์–ด์ง€๋‹ˆ๊นŒ..) 

๋”ฐ๋ผ์„œ @Query ๊ธฐ๋Šฅ์„ ํ›จ์”ฌ ๋งŽ์ด ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•œ๋‹ค~~ 

 

 

๐Ÿ™‚ @Query ๊ฐ’ DTO๋กœ ์กฐํšŒํ•˜๊ธฐ 

JPA ํ™œ์šฉํŽธ์„ ๋“ฃ๋‹ค๋ณด๋ฉด ์•Œ ์ˆ˜ ์žˆ๋Š” ๋‚ด์šฉ์ธ๋ฐ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ง์ ‘ ๋ฐ˜ํ™˜ํ•ด์„œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋…ธ์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๊ถŒ์žฅํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— DTO๋กœ ๋ณ€ํ™˜ํ•ด์„œ ๋ฐ˜ํ™˜ํ•˜๋ผ๊ณ  ํ•œ๋‹ค. 

 

๊ทธ๋Ÿด๋•Œ ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA์—์„œ๋„ JPA์™€ ๋™์ผํ•œ ๋ฐฉ์‹์„ ์ œ๊ณตํ•ด์ค€๋‹ค. 

 

MemberDto

-> MemberDto์—๋Š” id์™€ username, teamName ์ •๋„๋งŒ ํ•„์š”ํ•˜๋‹ค๊ณ  ๊ฐ€์ •ํ•œ๋‹ค.

 

MemberRepository

๊ทธ๋ฆฌ๊ณ  @Query ์–ด๋…ธํ…Œ์ด์…˜ ์•ˆ์— Jpa ์˜ new ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•ด์„œ DTO๋กœ ์กฐํšŒํ•˜๊ณ ์ž ํ•˜๋Š” ๊ฐ’๋“ค์„ ๋‚˜์—ดํ•ด์ฃผ๋ฉด ๋˜๋Š”๋ฐ, 

์ด๋•Œ ํ•ด๋‹น ๊ฐ’๋“ค์ด ๋“ค์–ด๊ฐ€๋Š” ์ƒ์„ฑ์ž๊ฐ€ ํ•„์š”ํ•˜๋‹ค. 

 

MemberRepositoryTest

 

 

4๏ธโƒฃ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉ 

- ์œ„์น˜ ๊ธฐ๋ฐ˜
- ์ด๋ฆ„ ๊ธฐ๋ฐ˜ 

-> ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉ์—๋Š” ์œ„์น˜ ๊ธฐ๋ฐ˜๊ณผ ์ด๋ฆ„ ๊ธฐ๋ฐ˜ ๋‘๊ฐœ๊ฐ€ ์žˆ๋Š”๋ฐ ์œ„์น˜ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋ฉด ๋ณ€๊ฒฝ์ด ์ผ์–ด๋‚˜๋ฉด ์ „๋ถ€ ๋ฐ”๊ฟ”์ค˜์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์œ ์ง€๋ณด์ˆ˜์„ฑ์ด ์•ˆ์ข‹๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฆ„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•ด์ฃผ๋Š” ๊ฒƒ์ด ์ข‹๋‹ค! 

 

 

MemberRepository

-> :name์ด๋ฉด @Param("name") ํ•˜๊ณ  String username์ด๋ฉด ์ด์ œ username์œผ๋กœ ๋ฐ›์•„์˜จ ๊ฐ’์„  ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ jpa๊ฐ€ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉํ•ด์ค€๋‹ค. 

 

 

์ปฌ๋ ‰์…˜ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉ

: Collection ํƒ€์ž…์œผ๋กœ in์ ˆ ์ง€์›

 

MemberRepositoryTest

in ์ ˆ์„ ์‚ฌ์šฉํ•ด์„œ memberA์™€ memberB๋ฅผ ์กฐํšŒํ•ด์˜ค๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

 

5๏ธโƒฃ ๋ฐ˜ํ™˜ ํƒ€์ž… 

: ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA๋Š” ์œ ์—ฐํ•œ ๋ฐ˜ํ™˜ ํƒ€์ž…์„ ์ง€์›ํ•œ๋‹ค. 

 

MemberRepository

https://docs.spring.io/spring-data/jpa/docs/current/reference/ html/#repository-query-return-types

 

MemberRepositoryTest

-> ์กฐํšŒ ์ฟผ๋ฆฌ๋Š” ๋ชจ๋‘ ๋˜‘๊ฐ™์€๋ฐ ๋ฐ˜ํ™˜ ํƒ€์ž…๋งŒ ๋‹ค๋ฅด๊ฒŒ ์ด๋ฃจ์–ด์ง„๋‹ค. 

 

โ“ ์กฐํšŒ ๊ฒฐ๊ณผ๊ฐ€ ๋งŽ๊ฑฐ๋‚˜ ์—†๋‹ค๋ฉด..?

์ปฌ๋ ‰์…˜: 

    - ๊ฒฐ๊ณผ ์—†์Œ: ๋นˆ ์ปฌ๋ ‰์…˜ ๋ฐ˜ํ™˜ 

๋‹จ๊ฑด ์กฐํšŒ: 

   - ๊ฒฐ๊ณผ ์—†์Œ: null ๋ฐ˜ํ™˜ 

   - ๊ฒฐ๊ณผ๊ฐ€ 2๊ฑด ์ด์ƒ: javax.persistence.NonUniqueResultException ์˜ˆ์™ธ ๋ฐœ์ƒ 

 

โ— ์ฐธ๊ณ 

๋‹จ๊ฑด์œผ๋กœ ์ง€์ •ํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA๋Š” ๋‚ด๋ถ€์—์„œ JPQL์˜ Query.getSingleResult() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค. 

์ด ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ–ˆ์„ ๋•Œ, ์กฐํšŒ ๊ฒฐ๊ณผ๊ฐ€ ์—†์œผ๋ฉด NoResultException ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š”๋ฐ ๊ฐœ๋ฐœ์ž ์ž…์žฅ์—์„œ ๋‹ค๋ฃจ๊ธฐ๊ฐ€ ์ƒ๋‹นํžˆ ๋ถˆํŽธํ•˜๋‹ค.. 

์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA๋Š” ๋‹จ๊ฑด์„ ์กฐํšŒํ–ˆ์„ ๋•Œ ์ด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์˜ˆ์™ธ๋ฅผ ๋ฌด์‹œํ•˜๊ณ  ๋Œ€์‹ ์— NULL ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ด์ค€๋‹ค.

 

 

6๏ธโƒฃ ์ˆœ์ˆ˜ JPA ํŽ˜์ด์ง•๊ณผ ์ •๋ ฌ 

ํŽ˜์ด์ง• & ์ •๋ ฌ

 

- JPA ํŽ˜์ด์ง• ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ์ฝ”๋“œ 

MemberJpaRepository

JPQL์—์„œ ํŽ˜์ด์ง•ํ•  ๋•Œ๋Š” setFirstResult๋กœ ์ฒ˜์Œ ๊ฐ€์ ธ์˜ฌ ๊ฐ’์„ ์„ค์ •ํ•ด์ฃผ๊ณ , setMaxResult๋ฅผ ํ†ตํ•ด ๊ฐ€์ ธ์˜ฌ ๋ฐ์ดํ„ฐ ์ˆ˜๋ฅผ ์ง€์ •ํ•ด์ค€๋‹ค. 

 

๊ทธ๋ฆฌ๊ณ  ํŽ˜์ด์ง•ํ•  ๋•Œ totalCount๋„ ํ•„์š”ํ•œ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์€๋ฐ ์ด๋Ÿด ๋•Œ๋ฅผ ์œ„ํ•ด ๋”ฐ๋กœ ๋ฉ”์†Œ๋“œ๋ฅผ ํ•˜๋‚˜ ๋” ๋งŒ๋“ค์–ด์ค€๋‹ค. 

count ๊ฐ’์„ ๊ตฌํ•  ๋•Œ๋Š” ๊ตณ์ด order by๋ฅผ ํ•ด์ค„ ํ•„์š”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์„ฑ๋Šฅ ์ตœ์ ํ™”๋ฅผ ์œ„ํ•ด์„œ ์ •๋ ฌ์€ ์ƒ๋žตํ–ˆ๋‹ค. 

 

MemberJpaRepositoryTest

-> limit์„ ํ†ตํ•ด ํŽ˜์ด์ง•์„ ํ•˜๋Š” ์ฟผ๋ฆฌ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.  

๊ทธ๋ฆฌ๊ณ  ์ด๋•Œ offset์€ ์–ด์ฐจํ”ผ 0๋ถ€ํ„ฐ ์‹œ์ž‘์ด๋ผ ์ƒ๋žตํ•ด์ค€ ๊ฒƒ์ด๋‹ค. 

๊ทธ๋ฆฌ๊ณ  count๊ฐ’๋„ ๊ตฌํ•ด์˜จ ์ฟผ๋ฆฌ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

 

7๏ธโƒฃ ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ 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 ์ฟผ๋ฆฌ ์—†์ด ๊ฒฐ๊ณผ๋งŒ ๋ฐ˜ํ™˜ 

 

MemberRepository

Page๋Š” count ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์œผ๋กœ count ์ฟผ๋ฆฌ๋ฅผ ๋ถ„๋ฆฌํ•ด์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ง€์ •ํ•ด ์ค„ ์ˆ˜๋„ ์žˆ๋‹ค. 

๋‘๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์€ Pageable ์€ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์‹ค์ œ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ํ•ด๋‹น ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ org.springframework.data.domain.PageRequest ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. 

 

 

MemberRepositoryTest

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

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

(์ฐธ๊ณ ๋กœ ํŽ˜์ด์ง€๋Š” 0๋ถ€ํ„ฐ ์‹œ์ž‘ํ•œ๋‹ค.) 

 

โ— ์ฃผ์˜: page๋Š” ์‹œ์ž‘์ด 1๋ถ€ํ„ฐ๊ฐ€ ์•„๋‹ˆ๋ผ 0๋ถ€ํ„ฐ์ด๋‹ค. 

 

-> ๋ฐ˜ํ™˜ํƒ€์ž…์ด Page ์ผ๋•Œ๋Š” count ์ฟผ๋ฆฌ๋„ ํ•จ๊ป˜ ๋‚˜๊ฐ„๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

๋ฐ˜ํ™˜ ํƒ€์ž…์„ Slice๋กœ ๋ฐ”๊ฟ”์„œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์ด๋•Œ Slice์ผ ๋•Œ๋Š” ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๋ฉ”์†Œ๋“œ๋“ค์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๊ฒƒ๋“ค์€ ์ฃผ์„ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์คฌ๋‹ค. 

(๊ทธ๋ฆฌ๊ณ  MemberRepository ์ธํ„ฐํŽ˜์ด์Šค์˜ findByAge ๋ฉ”์†Œ๋“œ ๋ฐ˜ํ™˜ํƒ€์ž…๋„ Slice๋กœ ๋ณ€๊ฒฝํ•ด์ค˜์•ผ ํ•œ๋‹ค!!)

 

-> ์ด๋•Œ๋Š” count ์ฟผ๋ฆฌ๊ฐ€ ๋‚˜๊ฐ€์ง€ ์•Š๊ณ  select ํŽ˜์ด์ง• ์ฟผ๋ฆฌ๋งŒ ๋‚˜๊ฐ€๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. 

๊ทธ๋ฆฌ๊ณ  Slice๋กœ ํ•˜๋ฉด limit์ด 3์ด ์•„๋‹ˆ๋ผ 4๊ฐ€ ๋‚˜๊ฐ€๋Š”๋ฐ ์ด์œ ๋Š” limit+1์„ ์กฐํšŒํ•ด์„œ ๋‹ค์Œ ํŽ˜์ด์ง€ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด์„œ +1 ํ•ด์„œ ์กฐํšŒํ•ด์ค€๋‹ค. 

 

 

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

Page์˜ map ๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•ด์„œ Member ์—”ํ‹ฐํ‹ฐ๋ฅผ dto๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

 

8๏ธโƒฃ ๋ฒŒํฌ์„ฑ ์ˆ˜์ • ์ฟผ๋ฆฌ 

 

- JPA๋ฅผ ์‚ฌ์šฉํ•œ ๋ฒŒํฌ์„ฑ ์ˆ˜์ • ์ฟผ๋ฆฌ 

MemberJpaRepository

-> ๊ทธ๋ƒฅ jpql๋กœ update ์ฟผ๋ฆฌ๋ฅผ ์งฐ๋Š”๋ฐ ์ด๋•Œ m.age๊ฐ€ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ฃผ์–ด์ง„ age๋ณด๋‹ค ๊ฐ’์ด ํฌ๋ฉด ํ•ด๋‹น Member๊ฐ์ฒด์˜ age๋ฅผ +1์”ฉ ์ฆ๊ฐ€ํ•˜๋Š” ๋ฒŒํฌ ์ˆ˜์ • ์ฟผ๋ฆฌ์ด๋‹ค. 

 

MemberJpaRepositoryTest

 

- ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA๋ฅผ ์‚ฌ์šฉํ•œ ๋ฒŒํฌ์„ฑ ์ˆ˜์ • ์ฟผ๋ฆฌ 

MemberRepository

๋ฒŒํฌ์„ฑ ์ˆ˜์ •, ์‚ญ์ œ ์ฟผ๋ฆฌ์—๋Š” @Modifying ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. 

์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด org.hibernate.hql.internal.QueryExecutionRequestException: Not supported for DML operations ์˜ˆ์™ธ ๋ฐœ์ƒํ•œ๋‹ค. 

 

๐Ÿ˜Ž ๋ฒŒํฌ์„ฑ ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ๋‚˜์„œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ์ดˆ๊ธฐํ™”: @Modifying(clearAutomatically = true) 

: ์ด ์˜ต์…˜ ์—†์ด ํšŒ์–ธ์„ f indById๋กœ ๋‹ค์‹œ ์กฐํšŒํ•˜๋ฉด ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ๊ณผ๊ฑฐ ๊ฐ’์ด ๋‚จ์•„์„œ ๋ฌธ์ œ๊ฐ€ ๋  ์ˆ˜์žˆ๋‹ค.

๋”ฐ๋ผ์„œ ๋‹ค์‹œ ์กฐํšŒํ•ด์•ผํ•œ๋‹ค๋ฉด ๊ผญ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ์ดˆ๊ธฐํ™”ํ•ด์•ผํ•œ๋‹ค. 

 

 

MemberRepositoryTest

์›๋ž˜ ๋ฒŒํฌ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•œ ๋‹ค์Œ์—๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ flush ํ•ด์„œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ๋น„์›Œ์•ผ ๊ฐ™์€ ํŠธ๋žœ์žญ์…˜์•ˆ์—์„œ ๋‹ค๋ฅธ ๋กœ์ง์ด ์žˆ์„ ๋•Œ ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ์ด ๋ฐ˜์˜๋œ๊ฒƒ์„ ์กฐํšŒํ•˜๊ฑฐ๋‚˜ ํ•  ์ˆ˜ ์žˆ๋‹ค. 

๊ทธ๋Ÿฐ๋ฐ ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ jpa์—์„œ๋Š” ์ธํ„ฐํŽ˜์ด์Šค์—์„œ @Modifing ์–ด๋…ธํ…Œ์ด์…˜ ์ค‘ clearAutomatically ์˜ต์…˜์„ true๋กœ ์„ค์ •ํ•ด์ฃผ๋ฉด ๋”ฐ๋กœ flush๋ฅผ ์•ˆํ•ด์ค˜๋„ ์ž๋™์œผ๋กœ flush๋ฅผ ํ•ด์ค€๋‹ค! 

 

โ— ์ฐธ๊ณ 

๋ฒŒํฌ ์—ฐ์‚ฐ์€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ๋ฌด์‹œํ•˜๊ณ  ์‹คํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์žˆ๋Š” ์—”ํ‹ฐํ‹ฐ์˜ ์ƒํƒœ์™€ DB์— ์—”ํ‹ฐํ‹ฐ ์ƒํƒœ๊ฐ€ ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ๋‹ค. 

๊ถŒ์žฅํ•˜๋Š” ๋ฐฉ์•ˆ

1. ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์—†๋Š” ์ƒํƒœ์—์„œ ๋ฒŒํฌ ์—ฐ์‚ฐ์„ ๋จผ์ € ์‹คํ–‰ํ•œ๋‹ค. 

2. ๋ถ€๋“์ดํ•˜๊ฒŒ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์žˆ์œผ๋ฉด ๋ฒŒํฌ ์—ฐ์‚ฐ ์งํ›„์— ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค. 

 

 

 

9๏ธโƒฃ @EntityGraph

: ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋“ค์„ SQL ํ•œ๋ฒˆ์— ์กฐํšŒํ•˜๋Š” ๋ฐฉ๋ฒ• 

 

member -> team ์€ ์ง€์—ฐ๋กœ๋”ฉ ๊ด€๊ณ„์ด๋‹ค.

๋”ฐ๋ผ์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด team์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•  ๋•Œ ๋งˆ๋‹ค ์ฟผ๋ฆฌ๊ฐ€ ์‹คํ–‰๋˜๋Š” N + 1 ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. 

 

MemberRepositoryTest

 

member.getTeam().getName()์„ ํ•˜๋Š” ์ˆœ๊ฐ„ member์˜ ์ˆ˜๋งŒํผ select team์„ ์กฐํšŒํ•œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜์žˆ๋‹ค.

์ด๋Ÿฐ ๋ฌธ์ œ๋ฅผ N+ 1 ๋ฌธ์ œ๋ผ๊ณ  ํ•œ๋‹ค. 

 

์ด N + 1 ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ํ•œ๋ฒˆ์— ์กฐํšŒํ•˜๋ ค๋ฉด ํŽ˜์น˜ ์กฐ์ธ์ด ํ•„์š”ํ•˜๋‹ค. 

 

MemberRepository

 

MemberRepositoryTest

-> ํŽ˜์น˜ ์กฐ์ธ์„ ์‚ฌ์šฉํ•˜๋Š” ์ฝ”๋“œ๋กœ ๋ฐ”๊ฟ”์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋‹ˆ left outer join์„ ํ†ตํ•ด์„œ ํ•œ๋ฒˆ์— ์กฐํšŒํ•ด ์˜ค๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

 

EntityGraph

: ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA๋Š” JPA๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์—”ํ‹ฐํ‹ฐ ๊ทธ๋ž˜ํ”„ ๊ธฐ๋Šฅ์„ ํŽธ๋ฆฌํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๊ฒŒ ๋„์™€์ค€๋‹ค. 

์ด ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋ฉด JPQL ์—†์ด ํŽ˜์น˜ ์กฐ์ธ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. (JPQL + ์—”ํ‹ฐํ‹ฐ ๊ทธ๋ž˜ํ”„๋„ ๊ฐ€๋Šฅ) 

 

MemberRepository

-> findAll ๊ณตํ†ต ๋ฉ”์„œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œ ํ•ด์„œ @EntityGraph๋ฅผ ์ถ”๊ฐ€ํ•ด์คฌ๋‹ค. 

 

๊ทธ๋ฆฌ๊ณ  ๋‹ค์‹œ Test ์ฝ”๋“œ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฉด 

LEFT OUTER JOIN์„ ์‚ฌ์šฉํ•œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. 

์ด๋ ‡๊ฒŒ ๋ณด๋ฉด ๊ทธ๋ƒฅ EntityGraph๋Š” ์‚ฌ์‹ค์ƒ ํŽ˜์น˜ ์กฐ์ธ์˜ ๊ฐ„ํŽธ ์กฐ์ธ์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

 

๐Ÿ”Ÿ JPA Hint & Lock 

JPA Hint 

: JPA ์ฟผ๋ฆฌ ํžŒํŠธ(SQL ํžŒํŠธ๊ฐ€ ์•„๋‹ˆ๋ผ JPA ๊ตฌํ˜„์ฒด์—๊ฒŒ ์ œ๊ณตํ•˜๋Š” ํžŒํŠธ

 

MemberRepository

 

MemberRepositoryTest

-> ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•ด๋ณด๋ฉด findReadOnlyByUsername์€ readOnly๋กœ ์„ค์ •ํ•ด๋’€๊ธฐ ๋•Œ๋ฌธ์— setUsername์„ ํ†ตํ•ด ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•˜๋”๋ผ๋„ ๋ณ€๊ฒฝ๊ฐ์ง€๊ฐ€ ์ผ์–ด๋‚˜์ง€ ์•Š๋Š”๋‹ค. (๋ฌด์‹œํ•ด๋ฒ„๋ฆฐ๋‹ค๊ณ  ํ•œ๋‹ค?)

 

Lock 

MemberRepository

-> org.springframework.data.jpa.repository.Lock ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•œ๋‹ค. 

 

MemberRepositoryTest

ํ•ด๋‹น ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์ด๋Ÿฐ ์ฟผ๋ฆฌ๊ฐ€ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. 

Lock์— ๋Œ€ํ•ด์„œ๋Š” ์ด๋ ‡๊ฒŒ๋งŒ ์–˜๊ธฐํ•˜๊ณ  ๋นจ๋ฆฌ ๋„˜์–ด๊ฐ€๋ฒ„๋ ค์„œ ์ดํ•ด๊ฐ€ ์ž˜ ์•ˆ๋ผ์„œ ๋” ๊ฒ€์ƒ‰ํ•ด๋ดค๋‹ค. 

 

SELECT FOR UPDATE=๋™์‹œ์„ฑ ์ œ์–ด๋ฅผ ์œ„ํ•ด ํŠน์ •row์— ๋ฐฐํƒ€์  LOCK์„ ๊ฑฐ๋Š” ํ–‰์œ„
“๋ฐ์ดํ„ฐ ์ˆ˜์ •ํ•˜๋ ค๊ณ  ์ฐพ์€ ๊ฒƒ์ด๋‹ˆ, ๋‹ค๋ฅธ๋ถ„๋“ค์€ ๊ฑด๋“œ๋ฆฌ์ง€ ๋งˆ์„ธ์š”!”

 

PESSMISTIIC_WRITE ๋Š” ๋น„๊ด€์  ์ž ๊ธˆ์ด๋ผ๊ณ  ํ•œ๋‹ค.

๋น„๊ด€์  ์ž ๊ธˆ(Pessimistic Lock)

๋™์ผํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋™์‹œ์— ์ˆ˜์ •ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค๋Š” ๋น„๊ด€์ ์ธ ์ „์ œ๋กœ ์ž ๊ธˆ์„ ๊ฑฐ๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ƒํ’ˆ์˜ ์žฌ๊ณ ๋Š” ๋™์‹œ์— ๊ฐ™์€ ์ƒํ’ˆ์„ ์—ฌ๋Ÿฌ๋ช…์ด ์ฃผ๋ฌธํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋ฐ์ดํ„ฐ ์ˆ˜์ •์— ์˜ํ•œ ๊ฒฝํ•ฉ์ด ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค๊ณ  ๋น„๊ด€์ ์œผ๋กœ ๋ณด๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ ์ถฉ๋Œ๊ฐ์ง€๋ฅผ ํ†ตํ•ด์„œ ์ž ๊ธˆ์„ ๋ฐœ์ƒ์‹œํ‚ค๋ฉด ์ถฉ๋Œ๋ฐœ์ƒ์— ์˜ํ•œ ์˜ˆ์™ธ๊ฐ€ ์ž์ฃผ ๋ฐœ์ƒํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿด๊ฒฝ์šฐ ๋น„๊ด€์  ์ž ๊ธˆ์„ ํ†ตํ•ด์„œ ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค์ง€ ์•Š๊ณ  ์ •ํ•ฉ์„ฑ์„ ๋ณด์žฅํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋งŒ ์„ฑ๋Šฅ์ ์ธ ์ธก๋ฉด์€ ์†์‹ค์„ ๊ฐ์ˆ˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ฃผ๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์ œ๊ณตํ•˜๋Š” ๋ฐฐํƒ€์ž ๊ธˆ(Exclusive Lock)์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ถœ์ฒ˜: https://reiphiel.tistory.com/entry/understanding-jpa-lock [๋ ˆ์ดํ”ผ์—˜์˜ ๋ธ”๋กœ๊ทธ:ํ‹ฐ์Šคํ† ๋ฆฌ]

 

๋ฐฐํƒ€์  ์ž ๊ธˆ(Exclusive Lock)์„ ํš๋“ํ•˜๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์—์„œ READ, UPDATE, DELETE ํ•˜๋Š”๊ฒƒ์„ ๋ฐฉ์ง€ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

 

 

 

 

728x90