/jpashop

๐Ÿ’ป ORM ํ‘œ์ค€ JPA ํ”„๋กœ๊ทธ๋ž˜๋ฐ (ํšŒ์›, ์ƒํ’ˆ, ์ฃผ๋ฌธ)

Primary LanguageJava

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ

image

๋น„์˜์†

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์™€ ์ „ํ˜€ ๊ด€๊ณ„๊ฐ€ ์—†๋Š” ์ƒˆ๋กœ์šด ์ƒํƒœ

Member member = new Member("kim");

์˜์†

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ๊ด€๋ฆฌ๋˜๋Š” ์ƒํƒœ

Member member = new Member("kim");

EntityMangager em = entityManagerFactory.createEntityManager();
em.persist(member); // ์ด์ œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ๊ด€๋ฆฌํ•œ๋‹ค.

em.persist(member); ๋ฅผ ํ•œ๋‹ค๊ณ  DB์— ์ €์žฅ๋˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ์ปค๋ฐ‹ ํ˜น์€ flush() ์ดํ›„์— DB์— ์ €์žฅ๋œ๋‹ค. ๊ทธ์ „๊นŒ์ง€๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—๋งŒ ์กด์žฌ.

์ค€์˜์†

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ €์žฅ๋˜์—ˆ๋‹ค๊ฐ€ ๋ถ„๋ฆฌ๋œ ์ƒํƒœ

Member member = new Member("kim");

EntityMangager em = entityManagerFactory.createEntityManager();
em.detach(member);

๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์ค€์˜์†์„ ๋งŒ๋“ค ์ผ์€ ๊ฑฐ์˜ ์—†์Œ

ํŠธ๋žœ์žญ์…˜

  • em.persist() ํŠธ๋žœ์žญ์…˜์ด ์ปค๋ฐ‹๋˜๋ฉด์„œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ํ”Œ๋Ÿฌ์‹œ ๋œ๋‹ค. ์ด๋•Œ ํŠธ๋žœ์žญ์…˜๊ณผ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ์ข…๋ฃŒ๋œ๋‹ค.
  • em.findById() ์ €์žฅํ•œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•˜๋ฉด ์ƒˆ๋กœ์šด ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.

์—ฐ๊ด€ ๊ด€๊ณ„ ์ฐธ์กฐ ๋ฐ ์กฐ์ธ

์‹ค๋ฌด JPA์—์„œ๋Š” @OneToMany, @ManyToMany ์กฐ์ธ ์‚ฌ์šฉ์„ ์ง€์–‘ํ•œ๋‹ค. (@ManyToOne ๋„ ๋˜๋„๋ก์ด๋ฉด ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ํ•œ๋‹ค.)

DB์— ๊ด€๊ณ„๋ฅผ ๋งบ๋Š” ์ˆœ๊ฐ„ ๊ทœ๋ชจ๊ฐ€ ์ปค์งˆ ์ˆ˜๋ก ์ˆ˜์ •์— ์ œ์•ฝ์ด ๋”ฐ๋ฅด๊ณ , ์–‘๋ฐฉํ–ฅ ์—ฐ๊ด€๊ด€๊ณ„์—์„œ๋Š” ๋ฌดํ•œ๋ฃจํ”„ ๋“ฑ, ํŠนํžˆ JPA์—์„œ๋Š” ์˜์†์„ฑ ์ „์ด๋‚˜ ๊ณ ์•„๊ฐ์ฒด์— ๋Œ€ํ•œ ์ง€์‹์ด ๋ถ€์กฑํ•˜๋ฉด ๋ฏธ๊ถ์— ๋น ์ง€๊ธฐ ์‰ฝ์ƒ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

ํ•˜์ง€๋งŒ, ์•Œ๊ณ  ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๊ฑฐ์™€ ์‚ฌ์šฉํ•ด๋ณด์ง€ ์•Š๊ณ  ์‚ฌ์šฉํ•˜์ง€ ๋ง๋ผํ•˜์—ฌ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๊ฒƒ์€ ์ฒœ์ง€์ฐจ์ด ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ๋‹ค์–‘ํ•œ ์—ฐ๊ด€ ๊ด€๊ณ„ ์กฐ์ธ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•ด๋ณด๋ฉฐ ํ•™์Šตํ•œ๋‹ค.

์—”ํ‹ฐํ‹ฐ ๊ทธ๋ž˜ํ”„

์—”ํ‹ฐํ‹ฐ ์กฐํšŒ์‹œ์ ์— ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋“ค์„ ํ•จ๊ป˜ ์กฐํšŒํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

1. Named ์—”ํ‹ฐํ‹ฐ ๊ทธ๋ž˜ํ”„

@NamedEntityGraph๋กœ ์ •์˜ํ•œ๋‹ค.

@NamedEntityGraph(name = "Order.withMember", attributeNodes = {@NamedAttributeNode("member"})
@Entity
public class Order {
...
}

์—”ํ‹ฐํ‹ฐ ๊ทธ๋ž˜ํ”„ ์‚ฌ์šฉ

EntityGraph graph = em.getEntityGraph("Order.withMember");
Map hints = new HashMap();
hints.put("javax.persistence.fetchgraph", graph);

Order order = em.find(Order.class, orderId, hinst);

2. JPQL์—์„œ ์—”ํ‹ฐํ‹ฐ ๊ทธ๋ž˜ํ”„

List<Order> resultList =
  em.createQuery("select o from Order o where o.id = :orderId", Order.class
  .setParameter("orderId", orderId)
  .setHint("javax.persistence.fetchgraph", e.getEntityGraph("Order.withAll"))
  .getResultList();

์–ด๋…ธํ…Œ์ด์…˜

@Transactional(readonly = true)

๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๋Š” ํŠธ๋žœ์žญ์…˜์—์„œ ํ”Œ๋Ÿฌ์‹œ๋ฅผ ์ƒ๋žตํ•˜์—ฌ ์•ฝ๊ฐ„์˜ ์„ฑ๋Šฅ ํ–ฅ์ƒ์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.

@DiscriminatorColumn

Item ํด๋ž˜์Šค์˜ ํ•˜์œ„ ํด๋ž˜์Šค๋ฅผ ์‹๋ณ„ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋  ์ปฌ๋Ÿผ์„ ์ง€์ •ํ•˜๊ณ , @DiscriminatorValue๋Š” ๊ฐ ํ•˜์œ„ ํด๋ž˜์Šค๊ฐ€ ํ•ด๋‹น ์ปฌ๋Ÿผ์— ์ €์žฅ๋  ๊ฐ’์„ ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”์—์„œ DTYPE ์ปฌ๋Ÿผ์— 'A'๊ฐ’์„ ๊ฐ€์ง„ ๋ ˆ์ฝ”๋“œ๋Š” Album ์ธ์Šคํ„ด์Šค์— ํ•ด๋‹นํ•˜๊ณ , 'B'๊ฐ’์„ ๊ฐ€์ง„ ๋ ˆ์ฝ”๋“œ๋Š” Book์˜ ์ธ์Šคํ„ด์Šค์— ํ•ด๋‹นํ•ฉ๋‹ˆ๋‹ค.

N+1

์ง€์—ฐ๋กœ๋”ฉ์„ ์‚ฌ์šฉํ•˜๋˜, JPQL ํŽ˜์น˜ ์กฐ์ธ์„ ์‚ฌ์šฉํ•˜์ž.

  • @OneToOne, @ManyToOne: ๊ธฐ๋ณธ ํŽ˜์น˜ ์ „๋žต์€ ์ฆ‰์‹œ๋กœ๋”ฉ
  • @OneToMany, @ManyToMany: ๊ธฐ๋ณธ ํŽ˜์น˜ ์ „๋žต์€ ์ง€์—ฐ๋กœ๋”ฉ

๋”ฐ๋ผ์„œ ๊ธฐ๋ณธ๊ฐ’์ด ์ฆ‰์‹œ ๋กœ๋”ฉ์ธ @OnetoOne, @ManyToOne์€ fetch = FetchType.LAZY๋กœ ์„ค์ •ํ•ด์„œ ์ง€์—ฐ ๋กœ๋”ฉ ์ „๋žต์„ ์‚ฌ์šฉํ•˜๋„๋ก ํ•˜์ž.

์ฝ๊ธฐ ์ „์šฉ ์ฟผ๋ฆฌ ์„ฑ๋Šฅ ์ตœ์ ํ™”

์—”ํ‹ฐํ‹ฐ๊ฐ€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ๊ด€๋ฆฌ๋˜๋ฉด 1์ฐจ ์บ์‹œ๋ถ€ํ„ฐ ๋ณ€๊ฒฝ ๊ฐ์ง€๊นŒ์ง€ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ํ˜œํƒ์ด ๋” ๋งŽ๋‹ค. ํ•˜์ง€๋งŒ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋Š” ๋ณ€๊ฒฝ๊ฐ์ง€๋ฅผ ์œ„ํ•ด ์Šค๋ƒ…์ƒท ์ธ์Šคํ„ด์Šค๋ฅผ ๋ณด๊ด€ํ•˜๋ฏ€๋กœ ๋” ๋งŽ์€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด 100๊ฑด์˜ ๊ตฌ๋งค ๋‚ด์šฉ์„ ์ถœ๋ ฅํ•˜๋Š” ๋‹จ์ˆœํ™˜ ์กฐํšŒ๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž. ๊ทธ๋ฆฌ๊ณ  ์กฐํšŒํ•œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋‹ค์‹œ ์กฐํšŒํ•  ์ผ๋„ ์—†๊ณ  ์ˆ˜์ •ํ•  ์ผ๋„ ์—†์ด ๋”ฑ ํ•œ๋ฒˆ๋งŒ ํ™”๋ฉด์— ์ถœ๋ ฅํ•˜๋ฉด ๋œ๋‹ค. ์ด๋•Œ๋Š” ์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์„ ์ตœ์ ํ™” ํ•  ์ˆ˜ ์žˆ๋‹ค.

@Transactional(readOnlny = true)

์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ํ•˜์ด๋ฒ„๋„ค์ดํŠธ ์„ธ์…˜์˜ ํ”Œ๋Ÿฌ์‹œ ๋ชจ๋“œ๋ฅผ MANUAL๋กœ ์„ค์ •ํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ฐ•์ œ๋กœ ํ”Œ๋Ÿฌ์‹œ๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š๋Š” ํ•œ ํ”Œ๋Ÿฌ์‹œ๊ฐ€ ์ผ์–ด๋‚˜์ง€ ์•Š๋Š”๋‹ค. ๋”ฐ๋ผ์„œ ํŠธ๋žœ์žญ์…˜์„ ์ปค๋ฐ‹ํ•ด๋„ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ํ”Œ๋Ÿฌ์‹œ ํ•˜์ง€์•Š๋Š”๋‹ค. ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ํ”Œ๋Ÿฌ์‹œ ํ•˜์ง€ ์•Š์œผ๋‹ˆ ๋“ฑ๋ก, ์ˆ˜์ •, ์‚ญ์ œ๋Š” ๋‹น์—ฐํžˆ ๋™์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค. ํ•˜์ง€๋งŒ ํ”Œ๋Ÿฌ์‹œํ•  ๋•Œ ์ผ์–ด๋‚˜๋Š” ์Šค๋ƒ…์ƒท ๋น„๊ต์™€ ๊ฐ™์€ ๋ฌด๊ฑฐ์šด ๋กœ์ง๋“ค์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์„ฑ๋Šฅ์ด ํ–ฅ์ƒ๋œ๋‹ค. ํŠธ๋žœ์žญ์…˜ ๊ณผ์ •์€ ์ด๋ฃจ์–ด์ง€๋˜ ๋‹จ์ง€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ํ”Œ๋Ÿฌ์‹œํ•˜์ง€ ์•Š์„ ๋ฟ์ด๋‹ค.

@PersistenceContext ๋ž€?

  • EntityManager๋ฅผ ๋นˆ์œผ๋กœ ์ฃผ์ž…ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜
  • ์Šคํ”„๋ง์—์„œ๋Š” ์˜์†์„ฑ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด EntityManager๊ฐ€ ์กด์žฌ
  • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์‹œ์ž‘๋  ๋•Œ EntityManager๋ฅผ ๋งŒ๋“ค์–ด์„œ ๋นˆ์œผ๋กœ ๋“ฑ๋ก
  • ์ด ๋•Œ ์Šคํ”„๋ง์ด ๋งŒ๋“ค์–ด๋‘” EntityManager๋ฅผ ์ฃผ์ž…๋ฐ›์„ ๋•Œ ์‚ฌ์šฉ
  • @PersistenceContext๋กœ ์ง€์ •๋œ ํ”„๋กœํผํ‹ฐ์— ์•„๋ž˜ ๋‘ ๊ฐ€์ง€ ์ค‘ ํ•œ ๊ฐ€์ง€๋กœ EntityManager๋ฅผ ์ฃผ์ž…
  • EntityManagerFactory์—์„œ ์ƒˆ๋กœ์šด EntityManager๋ฅผ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ Transaction์— ์˜ํ•ด ๊ธฐ์กด์— ์ƒ์„ฑ๋œ EntityManager๋ฅผ ๋ฐ˜ํ™˜

@PersistenceContext๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์ด์œ 

EntityManager๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์ฃผ์˜ํ•ด์•ผ ํ•  ์ 

์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ์ ‘๊ทผํ•˜๋ฉด ๋™์‹œ์„ฑ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ ์“ฐ๋ ˆ๋“œ ๊ฐ„์—๋Š” EntityManager๋ฅผ ๊ณต์œ ํ•ด์„œ๋Š” ์•ˆ๋ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์Šคํ”„๋ง์€ ์‹ฑ๊ธ€ํ†ค ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘ํ•˜๊ธฐ์— ๋นˆ์€ ๋ชจ๋“  ์“ฐ๋ ˆ๋“œ๊ฐ€ ๊ณต์œ ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ @PersistenceContext์œผ๋กœ EntityManager๋ฅผ ์ฃผ์ž…๋ฐ›์•„๋„ ๋™์‹œ์„ฑ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š” ์ด์œ ๋Š”

  • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ดˆ๊ธฐํ™”๋˜๋ฉด์„œ @PersistenceContext์œผ๋กœ ์ฃผ์ž…๋ฐ›์€ EntityManager๋ฅผ Proxy๋กœ ๊ฐ์Œ‰๋‹ˆ๋‹ค.
  • ๊ทธ๋ฆฌ๊ณ  EntityManager ํ˜ธ์ถœ ์‹œ ๋งˆ๋‹ค Proxy๋ฅผ ํ†ตํ•ด EntityManager๋ฅผ ์ƒ์„ฑํ•˜์—ฌ Thread-Safe๋ฅผ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.