Skip to content

๐Ÿ› ๏ธ ๋ถ€๋ก : ์—ฌ์ฐจ์ €์ฐจ JPA ์ ์‘๊ธฐ

์ด๊ฑด์ฐฝ edited this page May 16, 2024 · 3 revisions

๊ฐœ์š”

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

ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ… ์ •๋ฆฌ

์ด์Šˆ ๋ฐœ์ƒ : detached entity passed to persist

1๏ธโƒฃ ๋ฌธ์ œ

ํšŒ์›์ด ๊ฐ€์ง„ ์ฟ ํฐ ์ด๋ ฅ(unused_coupon_book)์„ ํšŒ์›์ด ์ง์ ‘ ๊ด€๋ฆฌํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ด Cascade ALL๋กœ ์„ค์ •ํ–ˆ๋”๋‹ˆ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค.

@Entity
@Table(name = "member")
class MemberEntity(
    @ManyToMany(
        targetEntity = CouponEntity::class,
        cascade = [CascadeType.ALL],
    )
    @JoinTable(
        name = "unused_coupon_book",
        joinColumns = [JoinColumn(name = "member_id")],
        inverseJoinColumns = [JoinColumn(name = "coupon_id")],
    )
    var unusedCoupons: List<CouponEntity>,   
}

์ง€๋‚˜๊ฐ€๊ธฐ ์ „์— Cascade๋ฅผ ์ •๋ฆฌํ•ด๋ดค๋‹ค. Cascade ๋Š” ์—”ํ‹ฐํ‹ฐ ์ƒํƒœ์— ๋”ฐ๋ผ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ• ์ง€ ๊ฒฐ์ •ํ•˜๋Š” ์„ค์ •๊ฐ’์ด๋‹ค.

  • PERSIST : ์—”ํ‹ฐํ‹ฐ๋ฅผ ์˜์†ํ™” ํ•  ๋•Œ ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋„ ์˜์†ํ™”ํ•œ๋‹ค.
  • MERGE : ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ณ‘ํ•ฉํ•  ๋•Œ ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋„ ๋ณ‘ํ•ฉํ•œ๋‹ค.
  • REMOVE : ์—”ํ‹ฐํ‹ฐ ์‚ญ์ œํ•  ๋•Œ ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋„ ํ•จ๊ป˜ ์‚ญ์ œํ•œ๋‹ค.
  • REFRESH : ์—”ํ‹ฐํ‹ฐ ๊ฐฑ์‹ ํ•  ๋•Œ ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋„ ํ•จ๊ป˜ ๊ฐฑ์‹ ํ•œ๋‹ค.

2๏ธโƒฃ ์›์ธ

Cascade๋Š” unused_coupon_book ์„ ํƒ€๊ฒŸ์œผ๋กœ ํ•˜์ง€ ์•Š๊ณ  coupon entity์„ ํƒ€๊ฒŸ์œผ๋กœ ํ•œ๋‹ค.

์ฐธ๊ณ  ์ž๋ฃŒ : JPA Hibernate many-to-many cascading

์ง์ ‘ ํ…Œ์ŠคํŠธํ–ˆ์„ ๋•Œ CascadeType.Persist ์„ค์ •๊ณผ ํ•จ๊ป˜ member entity + coupon entity ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒฝ์šฐ coupon entity ๊ฐ€ ์ €์žฅ๋๋‹ค. CascadeType.Remove ์„ค์ •์€ member entity๊ฐ€ ์‚ญ์ œ๋˜๋ฉด coupon entity๊ฐ€ ์‚ญ์ œ๋˜์–ด์•ผ ํ•˜๋Š”๊ฒŒ ๊ทธ๋ ‡์ง€ ์•Š์•˜๋‹คโ€ฆ? ํ…Œ์ŠคํŠธ ๋ฐฉ๋ฒ•์ด ์ž˜๋ชป๋๋‚˜ ํ•ด์„œ entity manager๋กœ remove ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰ํ•ด๋„ ๋™์ž‘ํ•˜์ง€ ์•Š์•˜๋‹ค.

3.X ๋ฒ„์ „์œผ๋กœ ๋„˜์–ด์˜ค๋ฉด์„œ ๋™์ž‘์ด ๋ณ€๊ฒฝ๋๋‚˜ ์ƒ๊ฐ์ด ๋“ ๋‹คโ€ฆ ๊ด€๋ จ ๋ฌธ์„œ๋Š” ํ™•์ธํ•˜๊ธฐ ์–ด๋ ต๋‹ค.

3๏ธโƒฃ ํ•ด๊ฒฐ

์˜์† ์ƒํƒœ์—์„œ ๋ถ„๋ฆฌ๋œ(deteched) ์—”ํ‹ฐํ‹ฐ๋ฅผ persist() ๋ฉ”์„œ๋“œ๋กœ ์˜์†ํ™”ํ•  ๋•Œ ๋ฐœ์ƒํ•˜๋ฉฐ ๋‹ค์Œ ์ค‘ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•˜๋ฉด ๋œ๋‹ค.

  1. ์—ฐ๊ด€ ๊ด€๊ณ„ ๋งคํ•‘์„ ํ†ตํ•ด CouponEntity ๊ฐ€ ์กฐํšŒ๋จ.
  2. ์กฐํšŒ๋œ CouponEntity๊ฐ€ ์ค€์˜์† ์ƒํƒœ๊ฐ€ ๋จ.

ํšŒ์›์€ ์กด์žฌํ•˜๋Š” ์ฟ ํฐ์„ ์ฐพ์•„ ์—ฐ๊ด€ ๊ด€๊ณ„๋ฅผ ๋งบ๋Š”๋‹ค. ํšŒ์›์ด ์—†์–ด์ง€๋ฉด ์—ฐ๊ด€๋œ ์ฟ ํฐ์„ ์—†์–ด์ง€๋ฉด ์•ˆ๋œ๋‹ค. ๊ทธ๋ž˜์„œ coupon entity ์™€ ์˜์† ์ƒํƒœ๋ฅผ ์œ ์ง€ ํ•˜๋ฉฐ ์ˆ˜์ •๋  ์ด์œ ๋„ ์—†๋‹ค.

4๏ธโƒฃ ์ •๋ฆฌ

๐Ÿ› ๏ธ ์ •๋ฆฌ์ค‘

์ด์Šˆ ๋ฐœ์ƒ : could not initialize proxy - no Session

1๏ธโƒฃ ๋ฌธ์ œ

์„ธ์…˜์ด ์—†๋Š” ์ƒํƒœ๋กœ lazy ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•˜๊ฒŒ ๋˜๋ฉด ํ…… ๋น„์–ด ์žˆ์–ด์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋‹ค. JPA์—์„œ ์„ธ์…˜์€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ๊ฐ์ฒด์ด๋ฉฐ EntityManger๊ฐ€ ์„ธ์…˜ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. EntityManger๋ฅผ ํ†ตํ•ด ํŠธ๋žœ์žญ์…˜์„ ์‹คํ–‰ํ•˜๊ณ  ์ปค๋ฐ‹ํ•˜๋ฉฐ ํ•œ์ •์ ์ธ ์„ธ์…˜์„ ์—ด์–ด ์ง€์—ฐ ๋กœ๋”ฉ์ด ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•œ๋‹ค. ์ฆ‰, ์ง€์—ฐ ๋กœ๋”ฉ์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋‹ค์Œ์ฒ˜๋Ÿผ ํŠธ๋žœ์žญ์…˜ ๋‚ด๋ถ€์—์„œ ์ ‘๊ทผํ•ด์•ผ ํ•œ๋‹ค.

fun find() {
  em.transaction.begin()

  val member = repoository.find() // ๋ฐ์ดํ„ฐ ์กฐํšŒ ์˜์—ญ
  println(member.unusedCoupons.size) // ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ์˜์—ญ
  
  em.transaction.commit()
}

2๏ธโƒฃ ์›์ธ

๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์— ํŠธ๋žœ์žญ์…˜์„ ๊ด€๋ฆฌํ•˜๋‹ค ๋ณด๋‹ˆ ํ•˜์œ„ ๋ ˆ์ด์–ด์—์„œ JPA ๊ด€๋ จ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ ํ•  ์ˆ˜ ์—†์—ˆ๋‹ค. ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ ค๋ฉด ํ•˜์œ„ ๋ ˆ์ด์–ด๋„ ํŠธ๋žœ์žญ์…˜์œผ๋กœ ์ƒˆ๋กญ๊ฒŒ ๋ฌถ๊ฑฐ๋‚˜ ์ฆ‰์‹œ ๋กœ๋”ฉ์ด ๋˜๊ฒŒ ์„ค์ •ํ•ด์•ผ ํ•œ๋‹ค.

3๏ธโƒฃ ํ•ด๊ฒฐ

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด ์กฐํšŒํ•˜๋Š” ์˜์—ญ๊ณผ lazy ๋ฐ์ดํ„ฐ๋ฅผ ์ ‘๊ทผํ•˜๋Š” ์˜์—ญ์„ ๊ฐ™์€ ์„ธ์…˜(ํŠธ๋žœ์žญ์…˜)์œผ๋กœ ํฌํ•จ์‹œํ‚ค๊ฑฐ๋‚˜ ์ฆ‰์‹œ ๋กœ๋”ฉ์ด ๋˜๊ฒŒ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

  • ํŠธ๋žœ์žญ์…˜ ๋‹จ์œ„๋กœ ๋ฌถ๋Š”๋‹ค.
  • ์ฆ‰์‹œ ๋กœ๋”ฉ์ด ๋˜๊ฒŒ ํ•œ๋‹ค.

์ฃผ์˜ํ•  ์ ์€ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•œ ์ฝ”๋“œ๊ฐ€ ์ƒ์„ฑ๋œ ์ ์ธ๋ฐ, ์ฆ‰์‹œ ๋กœ๋”ฉ์„ ํ•˜๋Š” ๊ฒฝ์šฐ ํ…Œ์ŠคํŠธ๋กœ ์ธํ•ด ํ”„๋กœ๋•ํŠธ ์„ฑ๋Šฅ์ด ๋ณ€ํ™”ํ•œ๋‹ค๋Š” ๋ฌธ์ œ์ ์ด ์žˆ์—ˆ๊ณ , ํŠธ๋žœ์žญ์…˜์€ ์ด๋ฏธ ํŠธ๋žœ์žญ์…˜์ด ์‹คํ–‰๋˜๋ฉด ๊ธฐ์กด ํŠธ๋žœ์žญ์…˜์„ ์œ ์ง€ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์„ฑ๋Šฅ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์•˜๋‹ค. ๋˜ํ•œ ์ฆ‰์‹œ ๋กœ๋”ฉ ํ•  ๋งŒํผ ํ•ด๋‹น ํ•„๋“œ๊ฐ€ ํ•ญ์ƒ ํ•„์š”ํ•˜์ง€ ์•Š์•„์„œ ํŠธ๋žœ์žญ์…˜ ์˜์—ญ์„ ๋ฎ์–ด์“ฐ๋„๋ก ์ˆ˜์ •ํ–ˆ๋‹ค.

4๏ธโƒฃ ์ •๋ฆฌ

ํ…Œ์ŠคํŠธ ํ•  ๋•Œ JPA๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ๋Œ€๋ถ€๋ถ„์˜ ๋ ˆ์ด์–ด์— ํŠธ๋žœ์žญ์…˜์„ ๋ถ™์—ฌ์•ผ ํ•˜๋Š” ๋Œ€์ฐธ์‚ฌ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ์„ฑ๋Šฅ์—๋Š” ์ฐจ์ด๊ฐ€ ์—†์ง€๋งŒ ํ…Œ์ŠคํŠธ ๊ด€๋ฆฌ๊ฐ€ ์–ด๋ ค์›Œ์งˆ ์ˆ˜ ์žˆ๋‹ค. ์ ์ ˆํ•˜๊ฒŒ ์ž˜ ๊ณ ๋ฏผํ•ด์„œ ์„ ํƒํ•˜๋„๋ก ํ•˜์ž.

Clone this wiki locally