๋ฐ˜์‘ํ˜•

 

๋งค์ผ๋ฉ”์ผ ๋ฐฑ์—”๋“œ ์งˆ๋ฌธ์„ ์ฐธ๊ณ ํ•ด ๊ฐœ์ธ์ ์œผ๋กœ ํ•™์Šตํ•œ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•˜์˜€์Šต๋‹ˆ๋‹ค.
์˜ค๋ฅ˜๊ฐ€ ์žˆ๋‹ค๋ฉด ์–ธ์ œ๋“  ํ”ผ๋“œ๋ฐฑ ์ฃผ์‹œ๋ฉด ๋ฐ”๋กœ ๋ฐ˜์˜ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค..!

 

 

 

์‹œ์ž‘ํ•˜๊ธฐ์— ์•ž์„œ

 

JPA๋ž€?

 

JPA(Java Persistence API)๋Š” ์ž๋ฐ” ๊ฐ์ฒด๋ฅผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅํ•˜๊ณ  ๋ถˆ๋Ÿฌ์˜ค๋Š” ๋ฐฉ๋ฒ•์„ ์ •์˜ํ•œ ํ‘œ์ค€ API์ž„

 

=> ORM(Object-Relational Mapping) ๊ธฐ์ˆ ์„ ์ œ๊ณตํ•˜๋Š” ์ž๋ฐ”์˜ ๊ณต์‹ ํ‘œ์ค€์ž„

 

JPA๋Š” ์ž์ฒด์ ์œผ๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š๊ณ  Hibernate์™€ ๊ฐ™์€ ๊ตฌํ˜„์ฒด๊ฐ€ ํ•„์š”ํ•จ

 

 

EntityManager๋ž€?

 

EntityManager์— ๋Œ€ํ•ด ์•Œ๊ธฐ ์œ„ํ•ด์„  Persistence Context์— ๋Œ€ํ•ด ์•Œ์•„์•ผํ•จ

 

Persistence Context๋Š” ์—”ํ‹ฐํ‹ฐ๋ฅผ ์˜๊ตฌ ์ €์žฅํ•˜๋Š” ํ™˜๊ฒฝ์œผ๋กœ 1์ฐจ ์บ์‹ฑ, ์“ฐ๊ธฐ ์ง€์—ฐ, ๋ณ€๊ฒฝ ๊ฐ์ง€๋ฅผ ํ†ตํ•ด ์˜์† ๋กœ์ง์„ ํšจ์œจ์ ์œผ๋กœ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์คŒ

 

=> ์ด๋Ÿฌํ•œ ํšจ์œจ์ ์ธ ์˜์† ๋กœ์ง ์ˆ˜ํ–‰์„ ์œ„ํ•ด์„œ ์—”ํ‹ฐํ‹ฐ๋Š” Persistence Context(์˜์†์„ฑ ์ปจํ…์ŠคํŠธ)์— ๊ด€๋ฆฌ๋˜์–ด์•ผํ•จ

์ด๋Ÿฐ ์ž‘์—…์„ ๋„์™€์ฃผ๋Š” ๊ฒƒ์ด ๋ฐ”๋กœ EntityManager ์ž„

 

=> ์—”ํ‹ฐํ‹ฐ์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ , Persistence Context์™€ ์ƒํ˜ธ์ž‘์šฉํ•จ์œผ๋กœ์จ ์˜์† ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์—ญํ• ์„ ๊ฐ€์ง€๊ณ ์žˆ์Œ

 

์—”ํ‹ฐํ‹ฐ๋Š” Persistence Context์™€ ๊ด€๋ จํ•˜์—ฌ 4๊ฐ€์ง€ ์ƒํƒœ(๋น„์˜์†, ์˜์†, ์ค€์˜์†, ์‚ญ์ œ)๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Œ

1. ๋น„์˜์† ์ƒํƒœ๋Š” ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๊ฐ€ ์ƒˆ๋กœ ์ƒ์„ฑ๋˜์—ˆ์ง€๋งŒ, ์•„์ง Persistence Context์™€ ์—ฐ๊ด€๋˜์ง€ ์•Š์€ ์ƒํƒœ์ž„
(๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ๊ด€๋ จ์ด ์—†์œผ๋ฉฐ, ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋Š” ๋ฉ”๋ชจ๋ฆฌ ์ƒ์—๋งŒ ์กด์žฌ)

ex. 

Member member = new Member("JunGyo");

2. ์˜์† ์ƒํƒœ๋Š” ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๊ฐ€ Persistence Context์— ๊ด€๋ฆฌ๋˜๊ณ  ์žˆ๋Š” ์ƒํƒœ์ž„
(์—”ํ‹ฐํ‹ฐ์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์ž๋™์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋ฐ˜์˜๋จ)

ex.

em.persist(member); // ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” ์—”ํ‹ฐํ‹ฐ๊ฐ€๋จ
em.merge(detachedMember); // ์ค€์˜์† ์ƒํƒœ์˜ ์—”ํ‹ฐํ‹ฐ (detached ์ƒํƒœ)๋ฅผ ๋‹ค์‹œ ์˜์† ์ƒํƒœ๋กœ ๋ณ€๊ฒฝ
em.find(Member.class, 1L); // ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒ

3. ์ค€์˜์† ์ƒํƒœ๋Š” ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๊ฐ€ ํ•œ ๋ฒˆ Persistence Context์— ์˜ํ•ด ๊ด€๋ฆฌ๋˜์—ˆ์ง€๋งŒ, ํ˜„์žฌ๋Š” Persistence Context์™€ ๋ถ„๋ฆฌ๋œ ์ƒํƒœ์ž„
(์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ๋” ์ด์ƒ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋ฐ˜์˜๋˜์ง€ ์•Š์Œ)

=> ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ์ข…๋ฃŒ, ํŠธ๋žœ์žญ์…˜ ์ข…๋ฃŒ ๋“ฑ์œผ๋กœ๋„ ์ค€์˜์† ์ƒํƒœ๋กœ ์ „ํ™˜๋จ

ex.

em.detach(member);
em.clear();
em.close();

4. ์‚ญ์ œ ์ƒํƒœ๋Š” ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๊ฐ€ Persistence Context์—์„œ ์ œ๊ฑฐ๋œ ์ƒํƒœ์ž„
(์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๊ฐ€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์‚ญ์ œ๋จ)

ex.

em.remove(member);

 

๊ฒฐ๋ก ์ ์œผ๋กœ EntityManager๋Š” Persistence Context์˜ 1์ฐจ ์บ์‹œ๋กœ๋ถ€ํ„ฐ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์“ฐ๊ธฐ ์ง€์—ฐ ์ €์žฅ์†Œ์— ์žˆ๋Š” ์ฟผ๋ฆฌ๋“ค์„ flushํ•˜์—ฌ DB์™€ ๋™๊ธฐ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Œ

๋˜ํ•œ, JPQL์ด๋‚˜ Native Query๋ฅผ ์ด์šฉํ•ด ์ง์ ‘ DB๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ๋„ ์žˆ์Œ

 

JPQL์€ JPA๊ฐ€ ์ง€์›ํ•˜๋Š” ๋‹ค์–‘ํ•œ ์ฟผ๋ฆฌ ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๋กœ SQL์ด ํ…Œ์ด๋ธ”์„ ๋Œ€์ƒ์œผ๋กœ ์ฟผ๋ฆฌํ–ˆ๋‹ค๋ฉด ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋ฅผ ๋Œ€์ƒ์œผ๋กœ ์ฟผ๋ฆฌํ•˜๋Š” ๊ฐ์ฒด์ง€ํ–ฅ ์ฟผ๋ฆฌ์ž„

=> ๊ฒฐ๊ตญ JPQL์€ SQL๋กœ ๋ณ€ํ™˜๋จ

 

Hibernate ๋ž€?

 

Hibernate๋Š” JPA์˜ ๊ตฌํ˜„์ฒด ์ค‘ ํ•˜๋‚˜๋กœ, ๊ฐ์ฒด์™€ RDB๋ฅผ ๋งคํ•‘ํ•˜๋Š” ORM ํ”„๋ ˆ์ž„์›Œํฌ์ž„

 

  • Hibernate๋Š” JPA์˜ ํ‘œ์ค€ ๋ช…์„ธ๋ฅผ ๊ตฌํ˜„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž„

  • JPA๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ตฌํ˜„์ฒด๋ฅผ Hibernate, EclipseLink, OpenJPA ๋“ฑ์œผ๋กœ ์‰ฝ๊ฒŒ ๊ต์ฒด ๊ฐ€๋Šฅ

  • @Entity, @Table, @Column ๊ฐ™์€ ์–ด๋…ธํ…Œ์ด์…˜์„ ํ™œ์šฉํ•ด์„œ DB ํ…Œ์ด๋ธ”๊ณผ Java ํด๋ž˜์Šค๋ฅผ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ์Œ

  • Hibernate๋Š” SQL์ด ์•„๋‹ˆ๋ผ ๊ฐ์ฒด ์ง€ํ–ฅ์ ์ธ ์ฟผ๋ฆฌ ์–ธ์–ด JPQL์„ ์‚ฌ์šฉํ•จ
    (SQL๋„ ์‚ฌ์šฉ์€ ๊ฐ€๋Šฅ)

  • Lazy Loading (์ง€์—ฐ ๋กœ๋”ฉ) ์ง€์›

    => ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ํ•„์š”ํ•  ๋•Œ๋งŒ ์กฐํšŒํ•˜๋„๋ก ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Œ

์˜ˆ๋ฅผ ๋“ค์–ด User์™€ Post๋ผ๋Š” ๋‘ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ–ˆ์„ ๋•Œ
User๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ Post๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋Š” @OnetoMany ๊ด€๊ณ„์ผ ์ˆ˜ ์žˆ์Œ

์ด ๋•Œ Lazy Loading ์ž‘๋™ ๋ฐฉ์‹์€

User ๊ฐ์ฒด๋ฅผ ์กฐํšŒํ•  ๋•Œ posts ๋ชฉ๋ก์€ ๋ฐ”๋กœ ์กฐํšŒ๋˜์ง€ ์•Š๊ณ  User ๊ฐ์ฒด๋งŒ DB์—์„œ ๊ฐ€์ ธ์˜ค๊ณ 
์ดํ›„, user.getPosts()๋ฅผ ํ˜ธ์ถœํ•˜๋ ค๊ณ  ํ•˜๋ฉด, ์‹ค์ œ DB์—์„œ Post ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•จ

Lazy Loading์˜ ์žฅ์ ์œผ๋กœ๋Š”

์ฒ˜์Œ์— ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋งŒ ๋กœ๋“œํ•˜๋ฏ€๋กœ ๋ถˆํ•„์š”ํ•œ DB ์กฐํšŒ๋ฅผ ์ค„์—ฌ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™” ํ•  ์ˆ˜ ์žˆ๊ณ 
๊ด€๋ จ๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ์‹ค์ œ๋กœ ํ•„์š”ํ•  ๋•Œ๋งŒ ๋กœ๋“œ๋˜๋ฏ€๋กœ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ์„ ์ค„์ผ ์ˆ˜ ์žˆ์Œ

LazyLoading์˜ ๋‹จ์ ์œผ๋กœ๋Š”

N+1 ๋ฌธ์ œ๊ฐ€ ์žˆ์Œ

=> ๋ถ€๋ชจ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋กœ๋“œํ•œ ํ›„์— ์ž์‹ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ ‘๊ทผํ•  ๋•Œ ์ถ”๊ฐ€ ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ ์„ฑ๋Šฅ ์ €ํ•˜๊ฐ€ ์ผ์–ด๋‚  ์ˆ˜ ์žˆ์Œ

 

  • Hibernate๋Š” ์ž๋™์œผ๋กœ ํŠธ๋žœ์žญ์…˜์„ ๊ด€๋ฆฌํ•˜๊ณ , ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ฑ๋Šฅ์„ ๋†’์ด๊ธฐ ์œ„ํ•ด 1์ฐจ ์บ์‹œ, 2์ฐจ ์บ์‹œ๋ฅผ ์ง€์›ํ•จ

 

Spring Data JPA๋ž€?

 

Spring Data JPA๋Š” JPA๋ฅผ ๋” ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” Spring ๊ธฐ๋ฐ˜์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž„

 

=> ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ๊ฐ์ฒด(Entity) ๊ฐ„์˜ ๋งคํ•‘์„ ๋” ํŽธํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก JPA๋ฅผ ๊ฐ์‹ธ๋Š” ๊ธฐ์ˆ ์ž„

JPA์˜ ๋‹จ์ˆœ ๋ฐ˜๋ณต์ ์ธ ์ž‘์—…์„ ์ž๋™ํ™”ํ•ด ์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ผ๊ณ  ๋ณด๋ฉด๋จ

=> JpaRepository๋งŒ ๋งŒ๋“ค๋ฉด ๋ฉ”์„œ๋“œ ์ด๋ฆ„๋งŒ์œผ๋กœ๋„ ์ฟผ๋ฆฌ๋ฅผ ์ž๋™ ์ƒ์„ฑ ํ•ด์ฃผ๊ธฐ์— ์ฝ”๋“œ๊ฐ€ ํ›จ์”ฌ ๊ฐ„๊ฒฐํ•ด์ง€๊ณ  ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์‰ฌ์›Œ์ ธ์„œ ์ƒ์‚ฐ์„ฑ์ด ํ–ฅ์ƒ๋จ
(EntityManager๋ฅผ ์ง์ ‘ ์“ฐ์ง€ ์•Š์•„๋„ JpaRepository๊ฐ€ ์•Œ์•„์„œ ์ฒ˜๋ฆฌํ•ด์คŒ)

๊ฒฐ๋ก ์€ Spring์—์„œ JPA๋ฅผ ์‚ฌ์šฉํ• ๊ฑฐ๋ฉด Spirng Data JPA๋„ ํ•จ๊ป˜ ์“ฐ์ž!

 

 

JPA(Spring Data JPA)๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๋Š” ์–ด๋–ค์‹์œผ๋กœ?

 

 

JPA(Spring Data JPA)๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์ง์ ‘ SQL์„ ์ฃผ๊ณ  ๋ฐ›์•„์•ผํ•จ

=> JPA๋Š” ์ž๋ฐ” ๊ฐ์ฒด(Entity)์™€ DB ํ…Œ์ด๋ธ”์„ ์ž๋™์œผ๋กœ ๋งคํ•‘ํ•ด์ฃผ๊ธฐ์— SQL์„ ์ง์ ‘ ์ž‘์„ฑํ•  ํ•„์š” X

 

 

JPA ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ํฌ๊ฒŒ 2๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ์ฐพ์„ ์ˆ˜ ์žˆ์—ˆ์Œ

 

  • JDBC(Java Database Connectivity)๋ฅผ ์‚ฌ์šฉ

    => JDBC๋Š” SQL์„ ์ง์ ‘ ์จ์•ผ ํ•˜๊ณ , Connection, Statement, ResultSet์„ ๊ด€๋ฆฌํ•ด์•ผ ํ•ด์„œ JPA์— ๋น„ํ•ด ์ƒ๋Œ€์ ์œผ๋กœ ์ฝ”๋“œ๊ฐ€ ๋ณต์žก

    (JPA๋„ ๊ฒฐ๊ตญ ๋‚ด๋ถ€์ ์œผ๋กœ JDBC๋ฅผ ์‚ฌ์šฉํ•จ)

  • MyBatis ์‚ฌ์šฉ (SQL Mapper)

    => MyBatis๋Š” SQL์„ XML ํŒŒ์ผ์ด๋‚˜ ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ๋”ฐ๋กœ ๊ด€๋ฆฌํ•ด์„œ, SQL์„ ์‰ฝ๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Œ
    (๋˜‘๊ฐ™์ด SQL์„ ์ง์ ‘ ์ž‘์„ฑํ•ด์•ผํ•˜์ง€๋งŒ JDBC๋ณด๋‹ค ๊น”๋”ํ•˜๊ฒŒ SQL์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Œ)

๊ทธ๋ ‡๋‹ค๋ฉด ๋ฌด์กฐ๊ฑด JPA๋งŒ ์จ์•ผํ• ๊นŒ?

 

 

JPA๋ฅผ ์“ฐ๋ฉด ์ข‹์€ ๊ฒฝ์šฐ

 

  • CRUD๊ฐ€ ๋งŽ๊ณ  SQL์„ ์ตœ๋Œ€ํ•œ ์ž๋™ํ™” ํ•˜๊ณ  ์‹ถ์„ ๋•Œ (Spring Data JPA ์‚ฌ์šฉ)

  • ๊ฐ์ฒด ์ค‘์‹ฌ์œผ๋กœ ๊ฐœ๋ฐœํ•˜๊ณ  ์‹ถ์„ ๋•Œ (OOP ์Šคํƒ€์ผ ์œ ์ง€ ๊ฐ€๋Šฅ)

    => SQL ์—†์ด ๊ฐ์ฒด ์ค‘์‹ฌ์œผ๋กœ ๊ฐœ๋ฐœ ๊ฐ€๋Šฅ

  • ์œ ์ง€๋ณด์ˆ˜๋ฅผ ์‰ฝ๊ฒŒ ํ•˜๊ณ  ์‹ถ์„ ๋•Œ (SQL์„ ์ตœ์†Œํ™”ํ•˜๊ณ  ์ฝ”๋“œ๋งŒ ๊ด€๋ฆฌ)

 

JPA๋ฅผ ์•ˆ ์“ฐ๋Š” ๊ฒฝ์šฐ

 

  • ๋ณต์žกํ•œ SQL ํŠœ๋‹์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ

  • ๋ ˆ๊ฑฐ์‹œ ํ”„๋กœ์ ํŠธ์—์„œ ๊ธฐ์กด SQL์„ ์œ ์ง€ํ•ด์•ผ ํ•  ๋•Œ

  • ๋‹จ์ˆœํ•œ ๋ฐ์ดํ„ฐ ์กฐํšŒ๋งŒ ํ•„์š”ํ•˜๊ณ , ORM์ด ์˜คํžˆ๋ ค ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ํด ๋•Œ

 


 

https://velog.io/@adam2/JPA๋Š”-๋„๋ฐ์ฒด-๋ญ˜๊นŒ-orm-์˜์†์„ฑ-hibernate-spring-data-jpa

 

 

=> JPA๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ RDB์™€ ๋งคํ•‘์„ ์œ„ํ•œ ๊ธฐ์ˆ ์ด๊ธฐ์— NoSQL์€ JPA๋ฅผ ํ™•์žฅํ•˜์—ฌ NoSQL ์ง€์›์„ ์ถ”๊ฐ€ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ (ex. Hibernate-OGM) ๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์ „์šฉ ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ (ex. MongoDB Java Driver) ๋ฅผ ์‚ฌ์šฉ

๋˜ํ•œ, ๊ทธ๋ฆผ์„ ์‚ดํŽด๋ณด๋ฉด JPA๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ JDBC ์‚ฌ์ด์—์„œ ๋™์ž‘ํ•˜๊ณ  ์žˆ๋Š”๋ฐ

๊ฐœ๋ฐœ์ž๊ฐ€ JPA๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, JPA ๋‚ด๋ถ€์—์„œ JDBC API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ SQL์„ ํ˜ธ์ถœํ•˜์—ฌ DB์™€ ํ†ต์‹ ํ•จ
(๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ JDBC ์‚ฌ์šฉ X)

 

JPA์˜ ddl-auto ์˜ต์…˜์€ ๊ฐ๊ฐ ์–ด๋–ค ๋™์ž‘์„ ํ•˜๊ณ  ์–ด๋–ค ์ƒํ™ฉ์—์„œ ์‚ฌ์šฉํ•ด์•ผ ํ• ๊นŒ?

 

ddl-auto ์˜ต์…˜์€ ์Šคํ”„๋ง ๋ถ€ํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ Hibernate์™€ ๊ฐ™์€ JPA ๊ตฌํ˜„์ฒด๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ‚ค๋งˆ ๊ด€๋ฆฌ๋ฅผ ์ œ์–ดํ•˜๋Š” ์„ค์ •์ž„

(application.properties ๋˜๋Š” application.yml ํŒŒ์ผ์—์„œ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Œ)

 

=> ๋‹ค์–‘ํ•œ ๊ฐ’์— ๋”ฐ๋ผ DB ์Šคํ‚ค๋งˆ์— ๋Œ€ํ•ด ๋‹ค๋ฅธ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•จ

 

  • none 

    => ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ‚ค๋งˆ์™€ ๊ด€๋ จ๋œ ์–ด๋– ํ•œ ์ž‘์—…๋„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š์Œ

    (์ˆ˜๋™์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์œ ์šฉํ•˜๋ฉฐ, ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ ์ฃผ๋กœ ์‚ฌ์šฉ)

  • validate

    => ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‹œ์ž‘๋  ๋•Œ, ์—”ํ‹ฐํ‹ฐ ๋งคํ•‘์ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ‚ค๋งˆ์™€ ์ผ์น˜ํ•˜๋Š”์ง€ ๊ฒ€์ฆํ•˜๋ฉฐ ์Šคํ‚ค๋งˆ ๋ณ€๊ฒฝ์€ ๋”ฐ๋กœ ์ˆ˜ํ–‰ X

    (ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ ์—”ํ‹ฐํ‹ฐ์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ‚ค๋งˆ๊ฐ€ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉ)

  • update

    => ์—”ํ‹ฐํ‹ฐ ๋งคํ•‘๊ณผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ‚ค๋งˆ๋ฅผ ๋น„๊ตํ•˜์—ฌ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์Šคํ‚ค๋งˆ๋ฅผ ์—…๋ฐ์ดํŠธํ•จ

    (๊ธฐ์กด ๋ฐ์ดํ„ฐ๋Š” ์œ ์ง€๋˜์ง€๋งŒ, ์ƒˆ๋กœ์šด ์—”ํ‹ฐํ‹ฐ๋‚˜ ๋ณ€๊ฒฝ๋œ ์—”ํ‹ฐํ‹ฐ ํ•„๋“œ๋Š” ์Šคํ‚ค๋งˆ์— ๋ฐ˜์˜๋˜๋ฏ€๋กœ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ๋Š” ์˜ˆ๊ธฐ์น˜ ์•Š์€ ์Šคํ‚ค๋งˆ ๋ณ€๊ฒฝ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•จ)

  • create

    => ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‹œ์ž‘๋  ๋•Œ ๊ธฐ์กด ์Šคํ‚ค๋งˆ๋ฅผ ์‚ญ์ œํ•˜๊ณ  ์ƒˆ๋กœ ์ƒ์„ฑํ•จ

    (๊ธฐ์กด ๋ฐ์ดํ„ฐ๊ฐ€ ๋ชจ๋‘ ์‚ญ์ œ๋˜๋ฏ€๋กœ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ๊ฐœ๋ฐœ ์ดˆ๊ธฐ์— ๋นˆ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ‚ค๋งˆ๋ฅผ ๋ฐ˜๋ณต์ ์œผ๋กœ ์ƒ์„ฑํ•ด์•ผํ•  ๋•Œ ์œ ์šฉํ•จ)

  • create-drop

    => create์™€ ์œ ์‚ฌํ•˜์ง€๋งŒ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ข…๋ฃŒ๋  ๋•Œ ์Šคํ‚ค๋งˆ๋ฅผ ์‚ญ์ œํ•จ

    (๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์—์„œ ์ผ์‹œ์ ์ธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ‚ค๋งˆ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์œ ์šฉํ•˜๋ฉฐ, ๋งค ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์‹œ๋งˆ๋‹ค ๊นจ๋—ํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๊ณ ์ž ํ•  ๋•Œ ์‚ฌ์šฉํ•จ)

 

ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ ์Šคํ‚ค๋งˆ ๋ณ€๊ฒฝ์€ ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ๊นŒ?

 

์Šคํ‚ค๋งˆ ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•  ๋•Œ๋Š” ์ ์ ˆํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋„๊ตฌ(Flyway, Liquibase ๋“ฑ)์„ ์‚ฌ์šฉํ•˜์—ฌ ์ œ์–ด๋œ ๋ฐฉ์‹์œผ๋กœ ์Šคํ‚ค๋งˆ๋ฅผ ๊ด€๋ฆฌํ•˜๊ฑฐ๋‚˜, ์‚ฌ์šฉ์ž๊ฐ€ ์—†๋Š” ์ƒˆ๋ฒฝ์— ์Šคํ‚ค๋งˆ ๋ณ€๊ฒฝ ์ž‘์—…์„ ์ˆ˜๋™์œผ๋กœ ์ง„ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ๋” ์•ˆ์ „ํ•  ์ˆ˜ ์žˆ์Œ

 

 

JPA์˜ N + 1 ๋ฌธ์ œ

 

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

์˜ˆ๋ฅผ ๋“ค์–ด, ๋ธ”๋กœ๊ทธ ๊ฒŒ์‹œ๊ธ€๊ณผ ๋Œ“๊ธ€์ด ์žˆ๋Š” ๊ฒฝ์šฐ, ๊ฒŒ์‹œ๊ธ€์„ ์กฐํšŒํ•œ ํ›„ ๊ฐ ๊ฒŒ์‹œ๊ธ€๋งˆ๋‹ค ๋Œ“๊ธ€์„ ์กฐํšŒํ•˜๊ธฐ ์œ„ํ•œ ์ถ”๊ฐ€ ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ

 

์ด๋ฅผ N + 1 ๋ฌธ์ œ๋ผ๊ณ  ํ•จ

 

์‰ฝ๊ฒŒ ๋งํ•˜๋ฉด ์กฐํšŒ ์‹œ 1๊ฐœ์˜ ์ฟผ๋ฆฌ๋ฅผ ์ƒ๊ฐํ•˜๊ณ  ์„ค๊ณ„ํ–ˆ๋Š”๋ฐ ๋‚˜์˜ค์ง€ ์•Š์•„๋„ ๋˜๋Š” ์กฐํšŒ์˜ ์ฟผ๋ฆฌ๊ฐ€ N๊ฐœ๊ฐ€ ๋” ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ

 

findAll ๋ฉ”์„œ๋“œ์˜ ๊ธ€๋กœ๋ฒŒ ํŒจ์น˜ ์ „๋žต ๋ณ„ N + 1 ๋ฌธ์ œ ์ƒํ™ฉ

 

findAll ๋ฉ”์„œ๋“œ๋Š” spring data jpa์—์„œ ์ œ๊ณตํ•˜๋Š” repository์˜ ๋ฉ”์„œ๋“œ์ด๊ณ 

๊ธ€๋กœ๋ฒŒ ํŒจ์น˜ ์ „๋žต(Global Fetch Strategy)์€ JPA์—์„œ ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์–ด๋–ป๊ฒŒ ๊ฐ€์ ธ์˜ฌ ๊ฒƒ์ธ์ง€๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ์ „๋žต์ž„

=> ์ฆ‰์‹œ๋กœ๋”ฉ, ์ง€์—ฐ๋กœ๋”ฉ ๋ฐฉ์‹์ด ์žˆ์Œ

 

 

๊ธ€๋กœ๋ฒŒ ํŒจ์น˜ ์ „๋žต์„ ์ฆ‰์‹œ๋กœ๋”ฉ์œผ๋กœ ์„ค์ •ํ•˜๊ณ  findAll()์„ ์‹คํ–‰ํ•˜๋ฉด N + 1 ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•จ

=> findAll()์ด select u from User u ๋ผ๋Š” JPQL ๊ตฌ๋ฌธ์„ ์ƒ์„ฑํ•ด์„œ ์‹คํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ

 

(JPQL์€ ๊ธ€๋กœ๋ฒŒ ํŒจ์น˜ ์ „๋žต์„ ๊ณ ๋ คํ•˜์ง€ ์•Š๊ณ  ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜๋Š”๋ฐ ๋ชจ๋“  User๋ฅผ ์กฐํšŒํ•˜๋Š” ์ฟผ๋ฆฌ ์‹คํ–‰ ํ›„, ์ฆ‰์‹œ๋กœ๋”ฉ ์„ค์ •์„ ๋ณด๊ณ  ์—ฐ๊ด€๊ด€๊ณ„์— ์žˆ๋Š” ๋ชจ๋“  ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•˜๋Š” ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ž„)

=> N + 1 ๋ฌธ์ œ๋Š” ๊ฒฐ๊ตญ ์ฟผ๋ฆฌ์˜ ๊ฐœ์ˆ˜๊ฐ€ ๋ฌธ์ œ์—ฌ์„œ ์ฆ‰์‹œ๋กœ๋”ฉ์ด ๋ฌด์Šจ ์ƒ๊ด€์ด์ง€๋ผ๊ณ  ์ƒ๊ฐํ–ˆ๋Š”๋ฐ ์ฆ‰์‹œ๋กœ๋”ฉ์ด ํ•œ ๋ฒˆ์˜ ์ฟผ๋ฆฌ๋กœ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ (์ด๊ฑด fetch join) ์ž๋™์œผ๋กœ ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋”ฐ๋กœ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ์‹์œผ๋กœ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ฟผ๋ฆฌ๊ฐ€ ์‹คํ–‰๋˜๋Š”๊ฑธ๋กœ ์ดํ•ดํ•˜์˜€์Œ 


 

๊ธ€๋กœ๋ฒŒ ํŒจ์น˜ ์ „๋žต์„ ์ง€์—ฐ ๋กœ๋”ฉ์œผ๋กœ ์„ค์ •ํ•˜๊ณ  findAll()์„  ์‹คํ–‰ํ•˜๋ฉด N + 1 ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์Œ

=> ์—ฐ๊ด€๊ด€๊ณ„์— ์žˆ๋Š” ์—”ํ‹ฐํ‹ฐ๋ฅผ ์‹ค์ œ ๊ฐ์ฒด ๋Œ€์‹  ํ”„๋ก์‹œ ๊ฐ์ฒด๋กœ ์ƒ์„ฑํ•˜์—ฌ ์ฃผ์ž…ํ•˜๊ธฐ ๋•Œ๋ฌธ
(ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” ๋‚˜์ค‘์— ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ๊ฐ€์งœ๋กœ ๋งŒ๋“ค์–ด์ง„ ๊ฐ์ฒด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด๋จ)

 

ํ•˜์ง€๋งŒ ์ด๋ ‡๊ฒŒ ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ์— ์‹ค์ œ ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•˜์—ฌ ์กฐํšŒํ•˜๋Š” ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ  N + 1 ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ

 

์ฆ‰์‹œ ๋กœ๋”ฉ(EAGER)์€ findAll() ์‹คํ–‰์‹œ N + 1 ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ ,

์ง€์—ฐ ๋กœ๋”ฉ(LAZY)์€ findAll() ์‹คํ–‰๋งŒ์œผ๋กœ๋Š” N + 1 ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์ง€๋งŒ, ์ดํ›„ ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜๋ฉด ๋ฐœ์ƒํ•จ

 

N + 1 ๋ฌธ์ œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

 

N + 1 ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” fetch join, @EntityGraph๋ฅผ ์‚ฌ์šฉํ•ด๋ณผ ์ˆ˜ ์žˆ์Œ

 

fetch join์€ ์—ฐ๊ด€ ๊ด€๊ณ„์— ์žˆ๋Š” ์—”ํ‹ฐํ‹ฐ๋ฅผ ํ•œ ๋ฒˆ์— ์ฆ‰์‹œ ๋กœ๋”ฉํ•˜๋Š” ๊ตฌ๋ฌธ์ž„

(JOIN์„ ๊ฐ•์ œํ•˜์—ฌ ํ•œ ๋ฒˆ์˜ ์ฟผ๋ฆฌ๋กœ ํ•ด๊ฒฐ)

select distinct u
from User u
left join fetch u.posts

 

 


@EnttiyGraph๋„ ๋น„์Šทํ•œ ํšจ๊ณผ๋ฅผ ๋งŒ๋“ค์–ด๋‚ด๋ฉฐ, ์ฟผ๋ฆฌ ๋ฉ”์„œ๋“œ์— ํ•ด๋‹น ์–ด๋…ธํ…Œ์ด์…˜์„ ์ถ”๊ฐ€ํ•ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ

 

@EntityGraph(attributePaths = {"posts"}, type = EntityGraphType.FETCH)
List<User> findAll();

 

 

Spring Data JPA์—์„œ ์ƒˆ๋กœ์šด Entity์ธ์ง€ ํŒ๋‹จํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ผ๊นŒ?

 

@Override
public boolean isNew(T entity) {

    if(versionAttribute.isEmpty()
          || versionAttribute.map(Attribute::getJavaType).map(Class::isPrimitive).orElse(false)) {
        return super.isNew(entity);
    }

    BeanWrapper wrapper = new DirectFieldAccessFallbackBeanWrapper(entity);

    return versionAttribute.map(it -> wrapper.getPropertyValue(it.getName()) == null).orElse(true);
}

(JpaMetamodelEntityInformation -> @Version ํ•„๋“œ์˜ ๊ฐ’์ด null ์ธ์ง€ ์—ฌ๋ถ€๋กœ ํŒ๋‹จ)

 

 

์ƒˆ๋กœ์šด Entity์ธ์ง€ ์—ฌ๋ถ€๋Š” JpaEntityInformation์˜ isNew(T entity)์— ์˜ํ•ด ํŒ๋‹จ๋จ

=> ๋‹ค๋ฅธ ์„ค์ •์ด ์—†์œผ๋ฉด JpaEntityInformation์˜ ๊ตฌํ˜„์ฒด ์ค‘ JpaMetamodelEntityInformation ํด๋ž˜์Šค๊ฐ€ ๋™์ž‘

 

@Version์ด ์‚ฌ์šฉ๋œ ํ•„๋“œ๊ฐ€ ์—†๊ฑฐ๋‚˜ @Version์ด ์‚ฌ์šฉ๋œ ํ•„๋“œ๊ฐ€ primitive ํƒ€์ž…(๊ธฐ๋ณธํ˜• ex. int, long ๋“ฑ)์ด๋ฉด AbstractEntityInformation์˜ isNew()๋ฅผ ํ˜ธ์ถœํ•จ

=> @Version์ด ์‚ฌ์šฉ๋œ ํ•„๋“œ๊ฐ€ wrapper class(ex. Integer, Long ๋“ฑ)์ด๋ฉด null ์—ฌ๋ถ€๋ฅผ ํ™•์ธ

Primitive Type์€ Stack์— ์œ„์น˜ํ•˜๋ฉฐ null์ด ํ—ˆ์šฉ๋˜์ง€ ์•Š๊ณ  (๊ฐ์ฒด X) Wrapper Class๋Š” Heap์— ์œ„์น˜ํ•˜๋ฉฐ null์ด ํ—ˆ์šฉ๋จ (๊ฐ์ฒด O)

 

@Version์ด๋ž€ Optimistic Lock์„ ์ ์šฉํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ๋™์‹œ์„ฑ ์ œ์–ด๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋ฉฐ, ํŠธ๋žœ์žญ์…˜ ์ถฉ๋Œ์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Œ

=> ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์ €์žฅ๋  ๋•Œ๋งˆ๋‹ค @Version ํ•„๋“œ ๊ฐ’์ด ์ฆ๊ฐ€ํ•˜๊ธฐ์— @Version ํ•„๋“œ๊ฐ€ null์ด๋ฉด ์ƒˆ๋กœ์šด ์—”ํ‹ฐํ‹ฐ๋ผ๊ณ  ํŒ๋‹จํ•  ์ˆ˜ ์žˆ์Œ

 

public boolean isNew(T entity) {

    Id id = getId(entity);
    Class<ID> idType = getIdType();

    if (!idType.isPrimitive()) {
        return id == null;
    }

    if (id instanceof Number) {
        return ((Number) id).longValue() == 0L;
    }

    throw new IllegalArgumentException(String.format("Unsupported primitive id type %s", idType));
}

 

(AbstractEntityInformation -> @Id ๊ฐ’์ด null์ธ์ง€ ์—ฌ๋ถ€๋กœ ํŒ๋‹จ)

 

@Version์ด ์‚ฌ์šฉ๋œ ํ•„๋“œ๊ฐ€ ์—†์–ด์„œ AbstractEntityInformation ํด๋ž˜์Šค๊ฐ€ ๋™์ž‘ํ•˜๋ฉด @Id ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•œ ํ•„๋“œ๋ฅผ ํ™•์ธํ•ด์„œ primitive ํƒ€์ž…์ด ์•„๋‹ˆ๋ผ๋ฉด null ์—ฌ๋ถ€, Number์˜ ํ•˜์œ„ ํƒ€์ž…์ด๋ฉด 0์ธ์ง€ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•จ

 

=> ์œ„ ์ฝ”๋“œ์—์„œ primitive ํƒ€์ž…์„ ์–ด๋–ป๊ฒŒ ๋‹ค๋ฃจ๋Š”๊ฑธ๊นŒ ๊ถ๊ธˆํ–ˆ๋Š”๋ฐ getId(entity) ๋ฉ”์„œ๋“œ๊ฐ€ ์ž๋™์œผ๋กœ Wrapper Class๋กœ Auto-Boxing (๋ณ€ํ™˜) ๋œ๋‹ค๊ณ  ํ•จ ๊ทธ๋ž˜์„œ, instanceof๋กœ Number ๋ผ๋ฉด 0์ธ์ง€ ํ™•์ธ (long, int ๊ฐ™์€ primitive ํƒ€์ž…์ด 0์œผ๋กœ ์ดˆ๊ธฐํ™” ๋˜๋ฏ€๋กœ)

 

 

@GeneratedValue ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ํ‚ค ์ƒ์„ฑ ์ „๋žต์„ ์‚ฌ์šฉํ•˜๋ฉด DB์— ์ €์žฅ๋  ๋•Œ id๊ฐ€ ํ• ๋‹น๋˜๊ธฐ ๋•Œ๋ฌธ์— DB์— ์ €์žฅ๋˜๊ธฐ ์ „ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์ƒ์„ฑ๋œ ๊ฐ์ฒด id๊ฐ€ ๋น„์–ด์žˆ์Œ

 

=> isNew()๋Š” true๊ฐ€ ๋˜์–ด ์ƒˆ๋กœ์šด entity๋กœ ํŒ๋‹จ

 

์ง์ ‘ ID๋ฅผ ํ• ๋‹นํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ์–ด๋–ค์‹์œผ๋กœ ๋™์ž‘ํ• ๊นŒ?

public class JpaPersistableEntityInformation<T extends Persistable<ID>, ID> 
        extends JpaMetamodelEntityInformation<T, ID> {

    public JpaPersistableEntityInformation(Class<T> domainClass, Metamodel metamodel, 
            PersistenceUnitUtil persistenceUnitUtil) {
        super(domainClass, metamodel, persistenceUnitUtil);
    }

    @Override
    public boolean isNew(T entity) {
        return entity.isNew();
    }

    @Nullable
    @Override
    public ID getId(T entity) {
        return entity.getId();
    }
}

 

JpaPersistableEntityInformation์˜ isNew()๊ฐ€ ๋™์ž‘ํ•จ

 

 

ํ‚ค ์ƒ์„ฑ ์ „๋žต์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์ง์ ‘ ID๋ฅผ ํ• ๋‹นํ•˜๋Š” ๊ฒฝ์šฐ ์ƒˆ๋กœ์šด entity๋กœ ๊ฐ„์ฃผ๋˜์ง€ ์•Š์Œ

=> ์œ„์—์„œ๋„ ์ ์–ด๋†จ์ง€๋งŒ @GeneratedValue ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ๋งŒ๋“  ํ‚ค๋Š” DB์— ์ €์žฅ๋˜๊ธฐ์ „ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์ƒ์„ฑ๋œ ๊ฐ์ฒด์˜ id๊ฐ€ ๋น„์–ด์žˆ์ง€๋งŒ ์ด๋ ‡๊ฒŒ id๋ฅผ ์ˆ˜๋™์œผ๋กœ ํ• ๋‹นํ•˜๋ฉด, entity๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์—์„œ๋ถ€ํ„ฐ id๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ์— ๊ธฐ๋ณธ JPA ํŒ๋‹จ ๊ธฐ์ค€๋Œ€๋กœ๋ผ๋ฉด ID๊ฐ€ ์กด์žฌํ•˜๋ฏ€๋กœ "๊ธฐ์กด ๋ฐ์ดํ„ฐ"๋กœ ๊ฐ„์ฃผ๋จ

 

public interface Persistable<ID> {
    ID getId();
    boolean isNew();  // ์ƒˆ๋กœ์šด ์—”ํ‹ฐํ‹ฐ์ธ์ง€ ํ™•์ธํ•˜๋Š” ๋ฉ”์„œ๋“œ
}

 

import org.springframework.data.domain.Persistable;
import jakarta.persistence.*;

@Entity
public class MyEntity implements Persistable<Long> {

    @Id
    private Long id;

    @Transient  // JPA๊ฐ€ ์ด ํ•„๋“œ๋ฅผ DB ์ปฌ๋Ÿผ์œผ๋กœ ์ €์žฅํ•˜์ง€ ์•Š๋„๋ก ํ•จ
    private boolean isNew = false;

    public MyEntity(Long id) {
        this.id = id;
        this.isNew = true;  // ์ˆ˜๋™์œผ๋กœ ID ํ• ๋‹นํ•  ๋•Œ ์ƒˆ๋กœ์šด ์—”ํ‹ฐํ‹ฐ๋กœ ๊ฐ„์ฃผ
    }

    @Override
    public boolean isNew() {
        return this.isNew;
    }

    @Override
    public Long getId() {
        return this.id;
    }

    @PostPersist // JPA์—์„œ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์ฒ˜์Œ persist๋œ ํ›„ ์‹คํ–‰๋˜๋Š” ๋ฉ”์„œ๋“œ
    @PostLoad // JPA์—์„œ ์—”ํ‹ฐํ‹ฐ๊ฐ€ DB์—์„œ ์กฐํšŒ(๋กœ๋”ฉ)๋œ ํ›„ ์‹คํ–‰๋˜๋Š” ๋ฉ”์„œ๋“œ
    public void markNotNew() {
        this.isNew = false;  // ์ €์žฅ๋˜๊ฑฐ๋‚˜ ๋กœ๋“œ๋œ ํ›„์—๋Š” ๊ธฐ์กด ์—”ํ‹ฐํ‹ฐ๋กœ ๊ฐ„์ฃผ
    }
}

 

์ด ๋•Œ๋Š” ์œ„์™€ ๊ฐ™์ด Entity์—์„œ Persistable<T> ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ด์„œ JpaMetamodelEntityInformation ํด๋ž˜์Šค๊ฐ€ ์•„๋‹Œ JpaPersistableEntityInformation์˜ isNew()๊ฐ€ ๋™์ž‘ํ•˜๋„๋ก ํ•ด์•ผํ•จ

 

Spring Data JPA๊ฐ€ isNew()๋ฅผ ํ˜ธ์ถœํ•ด์ฃผ๋Š” ๋ถ€๋ถ„์€ ์ œ๊ณต๋˜์ง€๋งŒ, isNew()๊ฐ€ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ• ์ง€๋Š” ์ง์ ‘ ๊ตฌํ˜„ํ•ด์•ผ ํ•จ

 

 

๊ทธ๋Ÿผ ์—ฌ๊ธฐ์„œ ๊ถ๊ธˆ์ฆ์ด ๋“œ๋Š” ๋ถ€๋ถ„์ด ์žˆ์„ ์ˆ˜ ์žˆ์Œ

Entity๊ฐ€ Persistable์„ ๊ตฌํ˜„ํ–ˆ๋Š”์ง€ ์–ด๋–ป๊ฒŒ ํŒ๋ณ„ํ•˜๊ณ  ํ๋ฆ„์ด ๋ญ˜๊นŒ?

 

Spring Data JPA๊ฐ€ Entity ์ •๋ณด๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ํ๋ฆ„

 

์šฐ์„  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ์‹œ JpaRepositoryFactory๊ฐ€ SimpleJpaRepository๋ฅผ ์ƒ์„ฑํ•˜๊ฒŒ๋จ

 

Spring Data JPA์—์„œ๋Š” JpaRepository๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์žˆ์œผ๋ฉด, ์ž๋™์œผ๋กœ ํ”„๋ก์‹œ(proxy) ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์„œ JpaRepositoryFactory์—์„œ ์ฒ˜๋ฆฌํ•˜๋„๋กํ•จ

JpaRepositoryFactory๋Š” ์š”์ฒญ๋ฐ›์€ ์—”ํ‹ฐํ‹ฐ ํƒ€์ž…์— ๋งž๊ฒŒ ์ ์ ˆํ•œ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๊ตฌํ˜„์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š”๋ฐ, ์ด๋•Œ ๊ธฐ๋ณธ์ ์œผ๋กœ SimpleJpaRepository๋ฅผ ์‚ฌ์šฉํ•จ

์ฆ‰, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ์‹œ JpaRepositoryFactory๊ฐ€ SimpleJpaRepository๋ฅผ ์ƒ์„ฑํ•ด์„œ ๋นˆ(bean)์œผ๋กœ ๋“ฑ๋ก

 

public class JpaRepositoryFactory extends RepositoryFactorySupport {

    private final EntityManager em;
    private final JpaMetamodelMappingContext context;

    public JpaRepositoryFactory(EntityManager entityManager) {
        this.em = entityManager;
        this.context = new JpaMetamodelMappingContext(entityManager.getMetamodel());
    }

    @Override
    protected <T, ID> JpaEntityInformation<T, ID> getEntityInformation(Class<T> domainClass) {
        Metamodel metamodel = em.getMetamodel();
        PersistentEntity<T, ID> entity = context.getRequiredPersistentEntity(domainClass);

        return Persistable.class.isAssignableFrom(domainClass)  // โœ… Persistable ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„ ์—ฌ๋ถ€ ํ™•์ธ
            ? new JpaPersistableEntityInformation<>(domainClass, metamodel, em.getPersistenceUnitUtil()) // โœ… Persistable ์‚ฌ์šฉ ์‹œ
            : new JpaMetamodelEntityInformation<>(domainClass, metamodel, em.getPersistenceUnitUtil());  // โœ… ์ผ๋ฐ˜ ์—”ํ‹ฐํ‹ฐ
    }

    @Override
    protected Object getTargetRepository(RepositoryInformation information) {
        JpaEntityInformation<?, ?> entityInformation = getEntityInformation(information.getDomainType()); // โœ… ์—ฌ๊ธฐ์„œ ํ˜ธ์ถœ๋จ

        return new SimpleJpaRepository<>(entityInformation, em);  // โœ… SimpleJpaRepository ์ƒ์„ฑ
    }

    @Override
    protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
        return SimpleJpaRepository.class;
    }
}

getEntityInformation ๋ถ€๋ถ„์—์„œ A.class.isAssignableFrom(B.class) => B๊ฐ€ A๋ฅผ ์ƒ์† ๋˜๋Š” ๊ตฌํ˜„ํ–ˆ๋‹ค๋ฉด ture


์ด ๋•Œ, Spring Data JPA๋Š” Repository๋ฅผ ๋งŒ๋“ค ๋•Œ Entity ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ณผ์ •์—์„œ ํ•ด๋‹น Entity๊ฐ€ Persistable์„ ๊ตฌํ˜„ํ–ˆ๋Š”์ง€ ์ž๋™์œผ๋กœ ํŒ๋‹จํ•จ

 

  • Persistable์„ ๊ตฌํ˜„ํ–ˆ๋‹ค๋ฉด JpaPersistableEntitiyInformation ์‚ฌ์šฉ

  • Persistable์„ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์•˜๋‹ค๋ฉด JpaMetamodleEntityInformation ์‚ฌ์šฉ

 

์ด๋ ‡๊ฒŒ ์ƒ์„ฑ๋œ JpaEntityInformation ๊ฐ์ฒด๋Š” SimpleJpaRepository์˜ ์ƒ์„ฑ์ž๋กœ ์ „๋‹ฌ๋จ (๋ฐ‘์˜ ์ฝ”๋“œ ์ฐธ๊ณ )

 

public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID> {
    
    private final JpaEntityInformation<T, ID> entityInformation;
    private final EntityManager em;

    public SimpleJpaRepository(JpaEntityInformation<T, ID> entityInformation, EntityManager em) {
        this.entityInformation = entityInformation; // โœ… ์ƒ์„ฑ์ž์—์„œ ํ• ๋‹น
        this.em = em;
    }
    
    @Override
    @Transactional
    public <S extends T> S save(S entity) {
        if (entityInformation.isNew(entity)) {
            em.persist(entity);
            return entity;
        } else {
            return em.merge(entity);
        }
    }
}

save ํ˜ธ์ถœ ์‹œ์—๋Š” SimpleJpaRepository์˜ save ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋จ (์ƒˆ๋กœ์šด entity๋ฉด persist, ์•„๋‹ˆ๋ฉด merge)

 

์ดํ›„ ์—”ํ‹ฐํ‹ฐ ์ €์žฅ ์š”์ฒญ์ด ์˜ค๋ฉด, SimpleJpaRepository.save()๊ฐ€ ์‹คํ–‰๋˜๋Š”๋ฐ 

entityInformation.isNew(entity)๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๊ฒŒ๋จ

 

์ƒˆ๋กœ์šด Entity์ธ์ง€ ํŒ๋‹จํ•˜๋Š”๊ฒŒ ์ค‘์š”ํ•œ ์ด์œ 

 

์œ„์˜ SimpleJpaRepository์˜ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ์•Œ ์ˆ˜ ์žˆ๋“ฏ, SimpleJpaRepository์˜ save() ๋ฉ”์„œ๋“œ์—์„œ isNew()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ persist๋ฅผ ์ˆ˜ํ–‰ํ• ์ง€ merge๋ฅผ ์ˆ˜ํ–‰ํ• ์ง€ ๊ฒฐ์ •ํ•จ

 

=> ๋งŒ์•ฝ ID๋ฅผ ์ง์ ‘ ์ง€์ •ํ•ด์ฃผ๋Š” ๊ฒฝ์šฐ์—๋Š” ์‹ ๊ทœ entity๋ผ๊ณ  ํŒ๋‹จํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— merge๋ฅผ ์ˆ˜ํ–‰

์ด ๋•Œ ํ•ด๋‹น entity๋Š” ์‹ ๊ทœ์ž„์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  DB๋ฅผ ์กฐํšŒํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋น„ํšจ์œจ์ ์ž„

๋”ฐ๋ผ์„œ, ์ƒˆ๋กœ์šด entity์ธ์ง€ ํŒ๋‹จํ•˜๋Š” ๊ฒƒ์€ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์ž„

 

์˜ˆ์‹œ ์ฝ”๋“œ๋Š” GPT ์„ ์ƒ๋‹˜์˜ ํž˜์„ ๋นŒ๋ ธ์Šต๋‹ˆ๋‹ค.
๋ฐ˜์‘ํ˜•