[๋„์ „ ๊ธฐ์ˆ !] JPA์™€ Querydsl

2021. 8. 25. 08:00ใ†Back-End ์ž‘์—…์‹ค/Spring Framework

728x90
๋ฐ˜์‘ํ˜•

์•ˆ๋…•ํ•˜์„ธ์š”? ์ฃผ๋‹ˆํ•˜๋ž‘ ์ž…๋‹ˆ๋‹ค.

๋ณธ ๋‚ด์šฉ์€ ์ฃผ๋‹ˆํ•˜๋ž‘์ด Web ๊ฐœ๋ฐœ ํ”„๋กœ์ ํŠธ๋ฅผ ํ•˜๋ฉด์„œ ๋„์ „ํ–ˆ๋˜ ๊ธฐ์ˆ ๋“ค์— ๋Œ€ํ•œ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•˜๋Š” ๊ณณ ์ž…๋‹ˆ๋‹ค!

์ด ๊ธ€์€ ํ•จ๊ป˜ ํ”„๋กœ์ ํŠธ ํ–ˆ๋˜ Back End ๊ฟˆ๋‚˜๋ฌด Crew๊ฐ€ ์ž‘์„ฑํ•œ ๊ฒƒ์ด์—์š”.

์ฃผ๋‹ˆํ•˜๋ž‘๋„ Back End ๊ฐœ๋ฐœ์„ ๋งก์•˜์—ˆ๋‹ต๋‹ˆ๋‹ค!

 

 

 

[์—์ด์ฝ˜์ถœํŒ]์Šคํ”„๋ง๊ณผ JPA๋ฅผ ํ™œ์šฉํ•œ ์ž๋ฐ” ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ ์„ธํŠธ - ์ „3๊ถŒ

COUPANG

www.coupang.com

"์ด ํฌ์ŠคํŒ…์€ ์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค ํ™œ๋™์˜ ์ผํ™˜์œผ๋กœ, ์ด์— ๋”ฐ๋ฅธ ์ผ์ •์•ก์˜ ์ˆ˜์ˆ˜๋ฃŒ๋ฅผ ์ œ๊ณต๋ฐ›์Šต๋‹ˆ๋‹ค."

 


 

 

โ“ ์ด๋ฒˆ ํ”„๋กœ์ ํŠธ์—์„œ ์šฐ๋ฆฌ๋Š” JPA๋ฅผ ์™œ ์‚ฌ์šฉํ–ˆ๋Š”๊ฐ€?

  • sql ์ค‘์‹ฌ์ ์ธ ๊ฐœ๋ฐœ์—์„œ ๊ฐ์ฒด ์ค‘์‹ฌ์ ์ธ ๊ฐœ๋ฐœ์ด ๊ฐ€๋Šฅ
  • ์ƒ์‚ฐ์„ฑ์ด ์ฆ๊ฐ€ํ•˜๊ณ  ๊ฐ„๋‹จํ•œ ๋ฉ”์„œ๋“œ๋กœ CRUD๊ฐ€ ๊ฐ€๋Šฅ
  • ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์‰ฝ๋‹คJPA: ํ•„๋“œ๋งŒ ์ถ”๊ฐ€, SQL์€ JPA๊ฐ€ ์ฒ˜๋ฆฌ
  • ๊ธฐ์กด: ํ•„๋“œ ๋ณ€๊ฒฝ ์‹œ ๋ชจ๋“  SQL์„ ์ˆ˜์ •
  • Object์™€ RDB ๊ฐ„์˜ ํŒจ๋Ÿฌ๋‹ค์ž„ ๋ถˆ์ผ์น˜ ํ•ด

 

๐Ÿ‘‰ JPA ์˜์†์„ฑ

JPA์˜ ํ•ต์‹ฌ์€ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ํฌํ•จ๋˜์–ด ์žˆ๋Š”์ง€ ์—†๋Š”์ง€๋กœ ๋‚˜๋‰ฉ๋‹ˆ๋‹ค. JPA์˜ ์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ €๊ฐ€ ํ™œ์„ฑํ™”๋œ ์ƒํƒœ๋กœ ํŠธ๋žœ์žญ์…˜(@Transactional) ์•ˆ์—์„œ DB์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋ฉด ์ด ๋ฐ์ดํ„ฐ๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ์œ ์ง€๋œ ์ƒํƒœ์ž…๋‹ˆ๋‹ค. ์ด ์ƒํƒœ์—์„œ ํ•ด๋‹น ๋ฐ์ดํ„ฐ ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋ฉด ํŠธ๋žœ์žญ์…˜์ด ๋๋‚˜๋Š” ์‹œ์ ์— ํ•ด๋‹น ํ…Œ์ด๋ธ”์— ๋ณ€๊ฒฝ ๋‚ด์šฉ์„ ๋ฐ˜์˜ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด์˜ ํ•„๋“œ ๊ฐ’๋งŒ ๋ณ€๊ฒฝํ•ด์ฃผ๋ฉด ๋ณ„๋„๋กœ update()์ฟผ๋ฆฌ๋ฅผ ๋‚ ๋ฆด ํ•„์š”๊ฐ€ ์—†๊ฒŒ ๋ฉ๋‹ˆ๋‹ค! ์ด ๊ฐœ๋…์„ ๋”ํ‹ฐ ์ฒดํ‚น์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

์˜์†์„ฑ ์ปจํ…Œ์ŠคํŠธ๋ž€?

์—”ํ‹ฐํ‹ฐ๋ฅผ ๋‹ด๊ณ  ์žˆ๋Š” ์ง‘ํ•ฉ.

JPA๋Š” ์˜์† ์ปจํ…์ŠคํŠธ์— ์†ํ•œ ์—”ํ‹ฐํ‹ฐ๋ฅผ DB์— ๋ฐ˜์˜ํ•œ๋‹ค. ์—”ํ‹ฐํ‹ฐ๋ฅผ ๊ฒ€์ƒ‰, ์‚ญ์ œ, ์ถ”๊ฐ€

ํ•˜๊ฒŒ ๋˜๋ฉด ์˜์† ์ปจํ…์ŠคํŠธ์˜ ๋‚ด์šฉ์ด DB์— ๋ฐ˜์˜๋œ๋‹ค. ์˜์† ์ปจํ…์ŠคํŠธ๋Š” ์ง์ ‘ ์ ‘๊ทผ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๊ณ  Entity Manager๋ฅผ ํ†ตํ•ด์„œ๋งŒ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

JPA ์„ฑ๋Šฅ ์ตœ์ ํ™”

  1. 1์ฐจ ์บ์‹œ์™€ ๋™์ผ์„ฑ๋ณด์žฅ
    • ๊ฐ™์€ ํŠธ๋ Œ์ ์…˜ ์•ˆ์—์„œ ๊ฐ™์€ Entity๋ฅผ ๋ฐ˜ํ™˜
    • SQL๋ฅผ ํ•œ๋ฒˆ๋งŒ ์‹คํ–‰
  2.  ์ง€์—ฐ๋กœ๋”ฉ
    • ๊ฐ์ฒด๊ฐ€ ์‹ค์ œ๋กœ ์‚ฌ์šฉ๋  ๋•Œ ๋กœ๋”ฉํ•˜๋Š” ์ „๋žต
    • Find ์˜ˆ์‹œ
Optional<DiscussionBoard> findById(@Param("id") Long id);

์˜ˆ์‹œ์ฒ˜๋Ÿผ ์ž‘์„ฑ์„ ํ•˜๊ฒŒ ๋˜๋ฉด id์— ๋Œ€ํ•œ ๊ฐ’์„ FindById ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด์„œ ๊ฐ’์„ ์กฐํšŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.์ฆ‰, ๊ฐ’์ด ์‹ค์ œ๋กœ ํ•„์š”ํ•œ ์‹œ์ ์— JPA๊ฐ€User์— ๋Œ€ํ•œ SELECT ์ฟผ๋ฆฌ๋ฅผ ๋‚ ๋ฆฐ๋‹ค.DiscussionBoard ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์— ๋Œ€๋ถ€๋ถ„ User๋„ ๊ฐ™์ด ํ•„์š”ํ•˜๋‹ค๋ฉด ์ฆ‰์‹œ ๋กœ๋”ฉ์„ ์‚ฌ์šฉํ•œ๋‹ค.์•„๋ž˜ ์‚ฌ์ง„์€ ์ƒ์„ธ ์กฐํšŒ๋ฅผ ํ–ˆ์„ ๋•Œ N + 1 ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์กฐํšŒ๋ฅผ ํ•  ๋•Œ ์—ฐ๊ด€ ๊ด€๊ณ„๊ฐ€ ์žˆ์œผ๋ฉด N + 1 ํ˜„์ƒ์ด ๋ฐœ๊ฒฌ์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ํ•œ๊ฐœ์˜ Query๋ฌธ๋งŒ ํ•„์š”ํ•˜์ง€๋งŒ JPA์—์„œ๋Š” ์—ฐ๊ด€๊ด€๊ณ„์— ์žˆ๋Š” ํ…Œ์ด๋ธ”๊นŒ์ง€ ๊ฐ™์ด ์กฐํšŒํ•ด์„œ ์กฐํšŒ๊ฐ€ 2๋ฒˆ์ด ๋˜๋Š” ํ˜„์ƒ์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. DiscussionBoard ์™€ User๊ฐ์ฒด ๊ฐ๊ฐ ๋”ฐ๋กœ ์กฐํšŒํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋„คํŠธ์›Œํฌ๋ฅผ 2๋ฒˆ ํƒ€๊ฒŒ ๋œ๋‹ค. Optional<DiscussionBoard> findById(@Param("id") Long id) ์—์„œ๋Š” DiscussionBoard ๊ฐ์ฒด์— ๋Œ€ํ•œ SELECT ์ฟผ๋ฆฌ๋งŒ ๋‚ ๋ฆฝ๋‹ˆ๋‹ค.

์ฆ‰, ๊ฐ’์ด ์‹ค์ œ๋กœ ํ•„์š”ํ•œ ์‹œ์ ์— JPA๊ฐ€User์— ๋Œ€ํ•œ SELECT ์ฟผ๋ฆฌ๋ฅผ ๋‚ ๋ฆฝ๋‹ˆ๋‹ค.

DiscussionBoard ์™€ User๊ฐ์ฒด ๊ฐ๊ฐ ๋”ฐ๋กœ ์กฐํšŒํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋„คํŠธ์›Œํฌ๋ฅผ 2๋ฒˆ ํƒ€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

DiscussionBoard ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์— ๋Œ€๋ถ€๋ถ„ User๋„ ๊ฐ™์ด ํ•„์š”ํ•˜๋‹ค๋ฉด ์ฆ‰์‹œ ๋กœ๋”ฉ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์กฐํšŒ๋ฅผ ํ•  ๋•Œ ์—ฐ๊ด€ ๊ด€๊ณ„๊ฐ€ ์žˆ์œผ๋ฉด N + 1 ํ˜„์ƒ์ด ๋ฐœ๊ฒฌ์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ํ•œ๊ฐœ์˜ Query๋ฌธ๋งŒ ํ•„์š”ํ•˜์ง€๋งŒ JPA์—์„œ๋Š” ์—ฐ๊ด€๊ด€๊ณ„์— ์žˆ๋Š” ํ…Œ์ด๋ธ”๊นŒ์ง€ ๊ฐ™์ด ์กฐํšŒํ•ด์„œ ์กฐํšŒ๊ฐ€ 2๋ฒˆ์ด ๋˜๋Š” ํ˜„์ƒ์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

์•„๋ž˜ ์‚ฌ์ง„์€ ์ƒ์„ธ ์กฐํšŒ๋ฅผ ํ–ˆ์„ ๋•Œ N + 1 ์ž…๋‹ˆ๋‹ค.

 

N+1์ด๋ž€

์—ฐ๊ด€ ๊ด€๊ณ„์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์ด์Šˆ๋กœ ์—ฐ๊ด€ ๊ด€๊ณ„๊ฐ€ ์„ค์ •๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•  ๊ฒฝ์šฐ์— ์กฐํšŒ๋œ ๋ฐ์ดํ„ฐ ๊ฐฏ์ˆ˜(n) ๋งŒํผ ์—ฐ๊ด€๊ด€๊ณ„์˜ ์กฐํšŒ ์ฟผ๋ฆฌ๊ฐ€ ์ถ”๊ฐ€๋กœ ๋ฐœ์ƒํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด์˜ค๊ฒŒ ๋œ๋‹ค.

๊ฒŒ์‹œํŒ ์ƒ์„ธ๋ณด๊ธฐ FindById ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉ ์‹œ ๊ฒŒ์‹œํŒ์— ๋Œ€ํ•œ Query๋ฌธ๊ณผ ์œ ์ €์— ๋Œ€ํ•œ Query๋ฌธ์ด ๊ฐ™์ด ๋‚˜์˜ค๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ FetchJoin์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

FetchJoin ์€ ์—ฐ๊ด€๊ด€๊ณ„๊ฐ€ ์žˆ๋Š” Entity๋ฅผ ํ•œ๋ฒˆ์— ์กฐํšŒ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์ด ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๋“ฃ๊ณ  ์ ์šฉ์„ ์‹œ์ผฐ์Šต๋‹ˆ๋‹ค.

 

Update ์˜ˆ์‹œ

queryRepository.updateBoard(update, board.getId(), board.getUser().getId());

 

์ˆ˜์ •์„ ํ•  ์‹œ์—๋„ Update ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ์‰ฝ๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

Update ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ ์ฟผ๋ฆฌ๋ฌธ์ž…๋‹ˆ๋‹ค.

 

Delete ์˜ˆ์‹œ

queryRepository.deleteBoard(board.getId(), board.getUser().getId());
728x90

์‚ญ์ œ๋ฅผ ํ•  ์‹œ์—๋„ Delete ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ญ์ œ ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

 

 

Delete๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ ์ฟผ๋ฆฌ๋ฌธ์ž…๋‹ˆ๋‹ค.

 

Querydsl์ด๋ž€?

  • JPQL์˜ ๋นŒ๋” ์—ญํ• ์„ ํ•˜๋Š” ์˜คํ”ˆ
  • Query๋ฅผ ์ž๋ฐ”์ฝ”๋“œ๋กœ ์ž‘์„ฑ
  • ํƒ€์ž… ์„ธ์ดํ”„

Querydsl๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด JPA๋ฅผ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ๋ณด๋‹ค ์ฟผ๋ฆฌ๋ฌธ์„ ์ง๊ด€์ ์œผ๋กœ ๋ณผ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

Querydsl๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” JPAQueryFactoryํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Q-Type์„ ์ด์šฉํ•ด์„œ Querydsl๋ฅผ ๋นŒ๋“œ ํ•ฉ๋‹ˆ๋‹ค.

  • Find Querydsl ์˜ˆ์‹œ
  • public Optional<DiscussionDetailResponse> findByDiscussionId(Long id){
    
            DiscussionDetailResponse board =
                    queryFactory
                            .select(Projections.constructor(DiscussionDetailResponse.class,
                                    discussionBoard.id,
                                    user.id,
                                    user.nickName,
                                    discussionBoard.title,
                                    discussionBoard.content,
                                    discussionBoard.createAt,
                                    discussionBoardReadhit.count))
                            .from(discussionBoard)
                            .innerJoin(discussionBoard.user, user)
                            .join(discussionBoardReadhit).on(discussionBoardReadhit.discussionBoard.id.eq(discussionBoard.id))
                            .where(discussionBoard.id.eq(id))
                            .fetchOne();
    
            return Optional.ofNullable(board);
    
        }

 

 

๊ฒŒ์‹œํŒ ๋ฒˆํ˜ธ๋ฅผ ์กฐํšŒํ•˜๋Š” ์ฟผ๋ฆฌ๋ฌธ์ž…๋‹ˆ๋‹ค. User์™€ DiscussionBoardReadhit์˜ ์ •๋ณด๋„ ์กฐํšŒ๋ฅผ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์—ฐ๊ด€๊ด€๊ณ„๊ฐ€ ์žˆ๋Š” Entity๋Š” inner join()์„ ์‚ฌ์šฉํ•˜๊ณ  ์—ฐ๊ด€๊ด€๊ณ„๊ฐ€ ์—†๋Š” Entity๋Š” join().on()์„ ์‚ฌ์šฉํ•ด์„œ N+1 ํ˜„์ƒ์„ ๋ง‰์œผ๋ฉด์„œ ์กฐํšŒ๋ฅผ ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

 

Querydsl๋กœ ์—ฐ๊ด€๊ด€๊ณ„์ธ User๋Š” innerjoin()์„ ์—ฐ๊ด€๊ด€๊ณ„๊ฐ€ ์—†๋Š” discussionReadhit์€ join().on()์„ ์ด์šฉํ•ด์„œ ์กฐํšŒํ•œ ์ฟผ๋ฆฌ๋ฌธ์ž…๋‹ˆ๋‹ค.

 

 

Update Querydsl ์˜ˆ์‹œ

public void updateBoard(DiscussionEditRequest update, Long id, Long userId) {

        JPAUpdateClause updateClause = new JPAUpdateClause(em, discussionBoard);

        updateClause
                .where(discussionBoard.id.eq(id), discussionBoard.user.id.eq(userId))
                .set(discussionBoard.title, update.getTitle())
                .set(discussionBoard.content, update.getContent())
                .set(discussionBoard.createAt, update.getCreateAt())
                .execute();
    }

Update์‹œ์—๋Š” JPAUpdateClaus๋ฅผ ์‚ฌ์šฉํ•ด์„œ where ์ ˆ๊ณผ set์„ ํ†ตํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

 

 

Update์‹œ์—๋Š” JPAUpdateClaus๋ฅผ ์‚ฌ์šฉํ•ด์„œ where ์ ˆ๊ณผ set์„ ํ†ตํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

 

Delete Querydsl ์˜ˆ์‹œ

public void deleteBoard(Long id, Long userId) {

        JPADeleteClause deleteClause = new JPADeleteClause(em, discussionBoard);

        deleteClause
                .where(discussionBoard.id.eq(id), discussionBoard.user.id.eq(userId))
                .execute();
    }

 

Delete์‹œ์—๋Š” JPADeleteClaus๋ฅผ ์‚ฌ์šฉํ•ด์„œ where์ ˆ์„ ํ†ตํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ญ์ œ ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

 

Querydsl๋ฅผ ์‚ฌ์šฉํ•ด์„œ Delete์‹œ ์ฟผ๋ฆฌ๋ฌธ์ž…๋‹ˆ๋‹ค.

 

 

 

[์—์ด์ฝ˜์ถœํŒ]์Šคํ”„๋ง๊ณผ JPA๋ฅผ ํ™œ์šฉํ•œ ์ž๋ฐ” ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ ์„ธํŠธ - ์ „3๊ถŒ

COUPANG

www.coupang.com

"์ด ํฌ์ŠคํŒ…์€ ์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค ํ™œ๋™์˜ ์ผํ™˜์œผ๋กœ, ์ด์— ๋”ฐ๋ฅธ ์ผ์ •์•ก์˜ ์ˆ˜์ˆ˜๋ฃŒ๋ฅผ ์ œ๊ณต๋ฐ›์Šต๋‹ˆ๋‹ค."

 

 

 

๊ฒฐ๋ก 

JPA์— ๋Œ€ํ•ด ๊ณต๋ถ€๋ฅผ ํ•˜๋ฉด์„œ ๋‹จ์ˆœ ๋ฉ”์†Œ๋“œ๋ช…์œผ๋กœ JPA๊ฐ€ ์•Œ์•„์„œ DB์— ๋ฐ์ดํ„ฐ๋ฅผ ๋“ฑ๋ก, ์กฐํšŒ, ์—…๋ฐ์ดํŠธ, ์‚ญ์ œ๋ฅผ ํ•ด์ฃผ๋Š” ๊ฒƒ์— ํŽธ๋ฆฌํ•˜๋‹ค๊ฒ ๋‹ค๋ผ๋Š” ์ƒ๊ฐ์„ ํ•˜๊ฒŒ ๋˜์—ˆ์ง€๋งŒ, ์ง์ ‘ JPA๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด์„œ Insert ๊ตฌ๋ฌธ์€ ์‚ฌ์šฉ์ž๊ฐ€ ์ž„์˜๋กœ ์ฟผ๋ฆฌ๋ฌธ์„ ์ž‘์„ฑํ•ด์„œ ์‹คํ–‰ ์‹œํ‚ฌ ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

Entity์—์„œ ์—ฐ๊ด€๊ด€๊ณ„์ธ ๊ฐ์ฒด๋ฅผ ์ง€์—ฐ๋กœ๋”ฉ์œผ๋กœ ์ง€์ •ํ•˜๋ฉด N+1๋ฅผ ๋ฐฉ์ง€ ํ•  ์ˆ˜ ์žˆ์„ ์ค„ ์•Œ์•˜์ง€๋งŒ DiscussionBoard์—์„œ User ์™€ ์—ฐ๊ด€๊ด€๊ณ„์— ์žˆ์œผ๋‹ˆ ์ฟผ๋ฆฌ๋ฌธ์ด 2๊ฐœ ๋ฐœ์ƒํ•˜์˜€์Šต๋‹ˆ๋‹ค. N+1 ํ˜„์ƒ์ด ๋ฐœ์ƒํ•˜๊ฒŒ ๋œ ๊ฒƒ์„ ์•Œ๊ฒŒ ๋˜์—ˆ๊ณ , ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ FetchJoin์„ ์ด์šฉํ•ด์„œ DiscussionBoard์™€ User ๊ฐ์ฒด๋ฅผ 1๊ฐœ์˜ ์ฟผ๋ฆฌ๋ฌธ์œผ๋กœ ์กฐํšŒ๋ฅผ ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

Querydsl์€ Entity Class ๋ฅผ wrapping ํ•œ Qxxx class ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— Entity Annotation์ด ์žˆ๋Š” ํด๋ž˜์Šค๋“ค์„ Qxxx class ๋กœ ์ž๋™ ์ƒ์„ฑํ•˜๋„๋ก ์„ค์ •ํ•ด์ฃผ๊ฒŒ๋˜๋ฉด ์ž๋ฐ”์ฝ”๋“œ๋ฅผ ์ด์šฉํ•ด์„œ Entity์™€ Qxxx type-safe๋ฅผ ํ†ตํ•ด์„œ DB์˜ ๊ฐ’์„ ์กฐํšŒ, ์ €์žฅ, ์‚ญ์ œ๋ฅผ ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

Querydsl์—์„œ N+1ํ˜„์ƒ์€ ์—ฐ๊ด€๊ด€๊ณ„์ธ ๊ฒฝ์šฐ์—๋Š” innerjoin(), ์—ฐ๊ด€๊ด€๊ณ„๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ์—๋Š” join().on()์„ ํ†ตํ•ด์„œ ๋ฐฉ์ง€ ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฒˆ ํ”„๋กœ์ ํŠธ์—์„œ JPA์™€ Querydsl๋ฅผ ์ด์šฉํ•ด์„œ DB์— ๊ฐ’์„ ์ €์žฅํ–ˆ์Šต๋‹ˆ๋‹ค.

 

728x90
๋ฐ˜์‘ํ˜•