JiwonDev

๋‚œ JPA๋ฅผ ์ œ๋Œ€๋กœ ์•Œ๊ณ  ์“ฐ๋Š” ๊ฒƒ์ธ๊ฐ€ (์ •๋ฆฌ์ค‘..)

by JiwonDev

# ๋ ˆํผ๋Ÿฐ์Šค

https://msolo021015.medium.com/jpa-persistence-context-deep-dive-2f36f9bd6214

 

JPA Persistence Context Deep Dive

์ตœ๊ทผ ์ €๋Š” ์ƒˆ๋กœ์šด ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด์„œ, JPA๋ฅผ ๋„์ž…ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

msolo021015.medium.com

#logging.level.org.hibernate.event.internal.AbstractFlushingEventListener=DEBUG

JPA๋ฅผ ์“ด๋‹ค๋ฉด OpenEntityManagerInViewFilter๋ฅผ ๊ณ ๋ คํ•ด์•ผํ•œ๋‹ค

 

JPA LazyLoading์€ ๊ด€๋ฆฌํ•˜๋Š” ์„ธ์…˜ ์‚ฌ์ดํด์— ํฌํ•จ๋˜์–ด ์žˆ์„ ๋•Œ๋งŒ๊ฐ€๋Šฅํ•˜๋‹ค.

ํŠธ๋žœ์žญ์…˜ ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚˜๋ฉด (View์— ์ „๋‹ฌ๋œ ์ดํ›„์—๋Š”) ์ฟผ๋ฆฌ ํ˜ธ์ถœ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค. ๊ทธ๋ž˜์„œ ํŠธ๋žœ์žญ์…˜์ด ๋๋‚˜๊ธฐ์ „ ์ง€์—ฐ๋กœ๋”ฉ์„ ๊ฐ•์ œ ํ˜ธ์ถœํ•ด์•ผํ•œ๋‹ค

 

๊ทธใ…ก๋ž˜์„œ Contoller๋ฅผ ๋ฒ—์–ด๋‚œ View๊นŒ์ง€ LazyLoading ํ•˜๊ธฐ์œ„ํ•ด OSIV(Open Session In View),

ํ•˜์ด๋ฒ„๋„ค์ดํŠธ์—์„  - OpenEntityManagerInViewFilter ์ด๋Ÿฐ๊ฒŒ ์žˆ๋‹ค.

 

ํŽธํ•˜๊ธด ํ•˜๊ธฐ๋งŒ, ์ตœ์ ํ™” ๊ด€์ ์—์„œ ์กฐ์‹ฌํ•ด์„œ ์จ์•ผํ•œ๋‹ค.

์ดˆ๋ณด ๊ฐœ๋ฐœ์ž๋Š” ์ฟผ๋ฆฌ๊ฐ€ ์‹คํ–‰๋˜๋Š” ์‹œ์ ์„ ์˜ˆ์ƒํ•˜์ง€ ๋ชปํ•œ๋‹ค. โžก ์„ฑ๋Šฅ ๋ฌธ์ œ๋กœ ๋ฐœ์ „ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค.

 

์š”์ฆ˜์—๋Š” SPA๊ฐ€ ์ƒ๊ฒจ์„œ ๊ทธ๋Ÿฐ๊ณ ๋ฏผ์„ ์•ˆํ•˜๊ธด ํ•œ๋‹ค. ๋งŒ์•ฝ ์„œ๋ฒ„์—์„œ ์ฒ˜๋ฆฌํ•œ๋‹ค ํ•œ๋“ค ์‚ฌ์šฉ์•ˆํ•˜๋Š” ๊ฒƒ๋„ ๊ณ ๋ ค. (SIde-Effect์™€ ์ดํ•ด๋„๋ฅผ ์œ„ํ•ด์„œ. @JsoinIgnore, @JsonView ๊ฐ™์€ ์„ ์–ธ์ด ๋งŽ์•„์ง€๋ฉด..ํด๋ž˜์Šค ์˜ˆ์ธก์ด ์–ด๋ ต๋‹ค)

 

DTO์˜ ๋ณ€ํ™”๋Š” ์™ธ๋ถ€ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์˜์‹ํ•ด์„œ ๊ด€๋ฆฌํ•˜๋Š” ๋ฒ”์œ„๊ฐ€ ๋œ๋‹ค. (Public, Swagger ์ŠคํŽ™ ํ™œ์šฉ)

์—ฌ๋Ÿฌ Entity๋ฅผ ์กฐํ•ฉํ•  ์ˆ˜ ์žˆ๋Š” ์—ฌ์ง€๊ฐ€ ์ƒ๊ธด๋‹ค.

 


EntityMangerFactory - ์•ฑ ์‹œ์ž‘์‹œ ์ƒ์„ฑ, Was ์ข…๋ฃŒ์‹œ ํ•จ๊ป˜ ์ข…๋ฃŒํ•˜๋ฉฐ ์ปค๋„ฅ์…˜ ํ’€์„ ๋ฐ˜ํ™˜ํ•จ

 

EntityManger - ๋‚ด๋ถ€์ ์œผ๋กœ DB Connetion pool ๊ฐ€์ง, ์„ธ์…˜์œผ๋กœ ์‚ฌ์šฉ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์Šค๋ ˆ๋“œ ๊ณต์œ  X

Persistence Context - Entity๊ฐ€ ์‹๋ณ„์ž๋กœ ๊ด€๋ฆฌ๋˜๋Š” ๊ณณ. ์—ฌ๋Ÿฌ EntityManager๊ฐ€ ๋™์‹œ์— ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Œ

 

1์ฐจ ์บ์‹œ (DB ์ฟผ๋ฆฌ ์•ˆ๋‚ ๋ฆฌ๊ธฐ)

- ์„ฑ๋Šฅ์ƒ ํฐ ์ด์  ์—†์Œ

 

1์ฐจ ์บ์‹œ ๋™์ž‘

โžก 1์ฐจ ์บ์‹œ์— ์กฐํšŒํ•˜๊ณ ์ž ํ•˜๋Š” Entity๊ฐ€ ์—†๋‹ค

โžก DB ์กฐํšŒ ์ฟผ๋ฆฌ๋ฅผ ๋‚ ๋ฆฐ๋‹ค

โžก Entity๋ฅผ ๊ฐ€์ ธ์™€์„œ P-Context์— ๋„ฃ๋Š”๋‹ค.

โžก ๋‹ค์Œ์— ๊ฐ™์€ ์‹๋ณ„์ž๋ฅผ ๊ฐ€์ง„ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์š”์ฒญํ•˜๋ฉด, DB์ฟผ๋ฆฌ๋ฅผ ๋‚ ๋ฆฌ์ง€ ์•Š๋Š”๋‹ค.

์ฆ‰, ์‹๋ณ„์ž(ID)๊ฐ€ ์•„๋‹Œ ๊ฐ’์œผ๋กœ ์ฟผ๋ฆฌ(JPQL)๋ฅผ ๋‚ ๋ฆฌ๊ฒŒ๋˜๋ฉด ์ƒˆ๋กญ๊ฒŒ ์กฐํšŒํ•ด๋ฒ„๋ฆฐ๋‹ค.

ID๋กœ ๊ฐ€์ ธ์˜ค๊ณ  ์ˆ˜์ •ํ–ˆ๋Š”๋ฐ, ์•„์ง DB Update๋ฅผ ๋‚ ๋ฆฌ์ง€์•Š์•˜๋‹ค. ํŠธ๋žœ์žญ์…˜ ์•ˆ๋‹ซ๊ณ  ๊ฐ’์œผ๋กœ ๊ฐ™์€๊ฑฐ ์กฐํšŒํ•˜๋ฉด ์ •ํ•ฉ์„ฑ ๊นจ์ง.

์•„, ๋ฌผ๋ก  JPQL์„ ์‚ฌ์šฉํ•˜๋ฉด Flush๊ฐ€ ๋˜๋„๋ก ๋งŒ๋“ค์–ด์ ธ์žˆ์œผ๋‹ˆ ์•ˆ์‹ฌํ•˜๋ผ.

 

โžก ์ด๋Ÿฐ ๋™์ž‘์€ ๋™์ผ์„ฑ ๋ณด์žฅ์—๋„ ์‚ฌ์šฉ๋œ๋‹ค. (ํ”„๋ก์‹œ๋ฅผ ์‚ฌ์šฉํ•ด๋„ ๋™์ผ์„ฑ์„ ๋ณด์žฅํ•˜๋„๋ก ๊ตฌํ˜„๋จ)

๊ทธ๋Ÿฌ๋‚˜ OSIV (Open Session In View ์„ธ์…˜์„ ๋ทฐ๊นŒ์ง€ ์œ ์ง€ํ•ด์„œ Lazy Loading๊ฐ€๋Šฅํ•˜๊ฒŒ)

ํ•˜์ด๋ฒ„๋„ค์ดํŠธ์—์„  OpenEntityManagerInViewFilter ๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” ๊ฑธ ์‚ฌ์šฉํ•˜๋ฉด ํŠธ๋žœ์žญ์…˜ ๋ฒ”์œ„๊ฐ€ ์•„๋‹ˆ๋ผ ์š”์ฒญ ๋ฒ”์œ„์˜ ์บ์‹œ๋กœ ๋„“์–ด์ง„๋‹ค. ์ด ๊ฒฝ์šฐ JPA๊ฐ€ ์ƒ์„ฑํ•˜๋Š” ์ฟผ๋ฆฌ๋ฅผ ์•Œ์ง€ ๋ชปํ•˜๋ฉด ์„ฑ๋Šฅ ๋ฐ•์‚ด๋‚  ์œ„ํ—˜์ด ์žˆ๋‹ค. 

 

Q. ๊ทธ๋Ÿผ 2์ฐจ์บ์‹œ๋Š” ๋ญ”๋ฐ?

์—ฌ๋Ÿฌ๋ช…์ด ์‚ฌ์šฉํ•˜๋Š” ์บ์‹œ, Application ์ „์ฒด์— ๊ณต์œ ํ•˜๋Š” ์บ์‹œ

์‚ฌ์‹ค JPA1.0์—๋Š” ์ ํ˜€์žˆ์ง€ ์•Š์€ ๊ธฐ๋Šฅ์œผ๋กœ, ๊ตฌํ˜„์ฒด๋งˆ๋‹ค ๋‹ค๋ฅธ ์บ์‹œ๊ธฐ๋Šฅ์„ ์ง€์›ํ•ด์คฌ์—ˆ๋‹ค.

JPA2.0๋ถ€ํ„ฐ ์บ์‹œ ํ‘œ์ค€์ด ๋‚˜์™”๊ณ  ์„ธ๋ฐ€ํ•œ ์„ค์ •์„ ํ•˜๊ธฐ์œ„ํ•ด์„  ๊ตฌํ˜„์ฒด์— ์˜์กด์ ์ธ ๊ธฐ๋Šฅ์„ ๋‹ค๋ค„์•ผํ•œ๋‹ค.

@Cacheable // 2์ฐจ์บ์‹œ ํ™œ์„ฑํ™”. true๋Š” ๊ธฐ๋ณธ ๊ฐ’์ด๋ผ ์ƒ๋žต๊ฐ€๋Šฅ @Cacheable(value=true)
@Entity
public class Member {
	@Id @GeneratedValue
    private Long id;
    
    ...
}
spring.jpa.properties.hibernate.cache.use_second_level_cache = true
๐Ÿ’จ 2์ฐจ ์บ์‹œ ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค.
spring.jpa.properties.hibernate.cache.region.factory_class
๐Ÿ’จ 2์ฐจ ์บ์‹œ๋ฅผ ์ฒ˜๋ฆฌํ•  ํด๋ž˜์Šค๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
spring.jpa.properties.hibernate.generate_statistics = true
๐Ÿ’จ ํ•˜์ด๋ฒ„๋„ค์ดํŠธ๊ฐ€ ์—ฌ๋Ÿฌ ํ†ต๊ณ„์ •๋ณด๋ฅผ ์ถœ๋ ฅํ•˜๊ฒŒ ํ•ด์ฃผ๋Š”๋ฐ ์บ์‹œ ์ ์šฉ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์ฐธ๊ณ ๋กœ @Cacheable์„ ์•ˆ๋ถ™์ด๊ณ  ์‚ฌ์šฉ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋ฐ”๊ฟ”์ค„ ์ˆ˜ ์žˆ๋‹ค.

 spring.jpa.properties.javax.persistence.sharedCache.mode= (๊ธฐ๋ณธ๊ฐ’) Enable_selective
  • ALL : ๋ชจ๋“  ์—”ํ‹ฐํ‹ฐ๋ฅผ ์บ์‹œํ•œ๋‹ค.
  • NONE : ์บ์‹œ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • ENABLE_SELECTIVE : Cacheable(true)๋กœ ์„ค์ •๋œ ์—”ํ‹ฐํ‹ฐ๋งŒ ์บ์‹œํ•œ๋‹ค.
  • DISABLE_SELECTIVE : ๋ชจ๋“  ์—”ํ‹ฐํ‹ฐ๋ฅผ ์บ์‹œํ•˜๋Š”๋ฐ Cacheable(false)๋กœ ๋ช…์‹œ๋œ ์—”ํ‹ฐํ‹ฐ๋Š” ์บ์‹œํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • UNSPECIFIED : JPA ๊ตฌํ˜„์ฒด๊ฐ€ ์ •์˜ํ•œ ์„ค์ •์„ ๋”ฐ๋ฅธ๋‹ค.

 

โžก JPA์—์„œ๋Š” ๊ณต์œ  ์บ์‹œ(Shared Cache, L2 Cahce)๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค. ๋ถ„์‚ฐ or ํด๋Ÿฌ์Šคํ„ฐ๋ง ํ™˜๊ฒฝ์—์„œ๋Š” Application์˜ ์ƒ๋ช…์ฃผ๊ธฐ ๋ณด๋‹ค ๋” ์˜ค๋ž˜ ์œ ์ง€๋˜๋Š” ๊ฒฝ์šฐ๋„ ์žˆ๋‹ค.

โžก EntityManager๋Š” 1์ฐจ ์บ์‹œ์— ์—†์œผ๋ฉด 2์ฐจ ์บ์‹œ์— ์ฐพ๊ณ , ๋˜ ์—†์œผ๋ฉด DB์—์„œ ์ฐพ๋Š”๋‹ค.

์ž˜ ํ™œ์šฉํ•˜๋ฉด ์กฐํšŒ ์„ฑ๋Šฅ์„ ํš๊ธฐ์ ์œผ๋กœ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

 

ํ•˜์ด๋ฒ„๋„ค์ดํŠธ 2์ฐจ ์บ์‹œ - 3๊ฐ€์ง€

  • ์—”ํ‹ฐํ‹ฐ ์บ์‹œ(JPA ํ‘œ์ค€) : ์—”ํ‹ฐํ‹ฐ ๋‹จ์œ„๋กœ ์บ์‹œํ•œ๋‹ค. ์‹๋ณ„์ž๋กœ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•˜๊ฑฐ๋‚˜ ์ปฌ๋ ‰์…˜์ด ์•„๋‹Œ ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋กœ๋”ฉํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.
  • ์ปฌ๋ ‰์…˜ ์บ์‹œ(์ „์šฉ๊ธฐ๋Šฅ) : ์—”ํ‹ฐํ‹ฐ์™€ ์—ฐ๊ด€๋œ ์ปฌ๋ ‰์…˜์„ ์บ์‹œํ•œ๋‹ค. ์ปฌ๋ ‰์…˜์ด ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋‹ด๊ณ  ์žˆ์œผ๋ฉด ์‹๋ณ„์ž ๊ฐ’๋งŒ ์บ์‹œํ•œ๋‹ค. 
  • ์ฟผ๋ฆฌ ์บ์‹œ(์ „์šฉ๊ธฐ๋Šฅ) : ์ฟผ๋ฆฌ์™€ ํŒŒ๋ผ๋ฏธํ„ฐ ์ •๋ณด๋ฅผ ํ‚ค๋กœ ์‚ฌ์šฉํ•ด์„œ ์บ์‹œํ•œ๋‹ค. ๊ฒฐ๊ณผ๊ฐ€ ์—”ํ‹ฐํ‹ฐ๋ฉด ์‹๋ณ„์ž ๊ฐ’๋งŒ ์บ์‹œํ•œ๋‹ค. 

@Cacheable
๐Ÿ’จ ์—”ํ‹ฐํ‹ฐ ์บ์‹œ ์ ์šฉ์‹œ ์‚ฌ์šฉํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜

@Cache
๐Ÿ’จ ํ•˜์ด๋ฒ„๋„ค์ดํŠธ ์ „์šฉ์ž…๋‹ˆ๋‹ค.

  • usage : CacheConcurrencyStrategy๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์บ์‹œ ๋™์‹œ์„ฑ ์ „๋žต์„ ์„ค์ •ํ•œ๋‹ค.
  • region : ์บ์‹œ ์ง€์—ญ ์„ค์ •
  • include : ์—ฐ๊ด€ ๊ฐ์ฒด๋ฅผ ์บ์‹œ์— ํฌํ•จํ• ์ง€ ์„ ํƒํ•œ๋‹ค. all, non-lazy ์˜ต์…˜์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์€ all์ด๋‹ค.

 

2์ฐจ ์บ์‹œ ๋™์ž‘

โžก ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋Š” 1์ฐจ ์บ์‹œ์— ์—†๋Š” ์—”ํ‹ฐํ‹ฐ๊ฐ€ ํ•„์š”ํ•˜๋ฉด 2์ฐจ ์บ์‹œ๋ฅผ ์กฐํšŒํ•œ๋‹ค.

โžก ๊ฑฐ๊ธฐ์—๋„ ์—†์œผ๋ฉด DB์— ์กฐํšŒํ•˜๊ณ , ๊ฒฐ๊ณผ๋ฅผ 2์ฐจ ์บ์‹œ์— ๋ณด๊ด€ํ•œ๋‹ค.

โžก 2์ฐจ ์บ์‹œ๋Š” ์ž์‹ ์ด ๋ณด๊ด€ํ•˜๊ณ  ์žˆ๋Š” ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ณต์‚ฌํ•ด์„œ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

โžก ์›๋ณธ์„ ์ฃผ๋Š”๊ฒŒ ์•„๋‹ˆ๋‹ค. ์กฐํšŒ์‹œ ๋ณต์‚ฌ๋ณธ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. (๋™์‹œ์„ฑ ๊ทน๋Œ€ํ™”)

์˜์†์„ฑ ์œ ๋‹› ๋ฒ”์œ„์˜ ์บ์‹œ์ด๋‹ค. ์‰ฝ๊ฒŒ ๋งํ•ด ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ๋‹ค๋ฅด๋‹ค๋ฉด ๊ฐ์ฒด ๋™์ผ์„ฑ์„ ์ „ํ˜€ ๋ณด์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค. 

 

 

์—”ํ‹ฐํ‹ฐ '๋“ฑ๋ก'์‹œ ํŠธ๋žœ์žญ์…˜์„ ์ง€์›ํ•˜๋Š” ์“ฐ๊ธฐ์ง€์›

์ฐธ๊ณ ๋กœ ์กฐํšŒ๋Š” ์ง€์—ฐ์ด ์•ˆ๋œ๋‹ค. ๋ญ๊ฐ€ ๋ฐ˜ํ™˜๋  ์ค„ ์–ด๋–ป๊ฒŒ ์•Œ๊ณ ?

์กฐํšŒ๊ฐ€ ์ง€์—ฐ๋˜๋ฉด ์กฐํšŒ ์‹œ์ ์— ๋”ฐ๋ผ ์ •ํ•ฉ์„ฑ์ด ๊นจ์ ธ๋ฒ„๋ฆด ์ˆ˜ ์žˆ๋‹ค. 

 

entityManager.persist(memberA)

 

1) memberA๊ฐ€ 1์ฐจ ์บ์‹œ์— ์ €์žฅํ•œ๋‹ค.
2) 1)๊ณผ ๋™์‹œ์— JPA๊ฐ€ Entity๋ฅผ ๋ถ„์„ํ•˜์—ฌ insert Query๋ฅผ ๋งŒ๋“ ๋‹ค.
3) insert Query๋ฅผ ์“ฐ๊ธฐ ์ง€์—ฐ SQL ์ €์žฅ์†Œ ๋ผ๋Š” ๊ณณ์— ์Œ“๋Š”๋‹ค.
4) DB์— ๋ฐ”๋กœ ๋„ฃ์ง€ ์•Š๊ณ  ๊ธฐ๋‹ค๋ฆฐ๋‹ค.
5) memberB๋„ ๋™์ผ.

 

transaction.commit()

6) ์“ฐ๊ธฐ ์ง€์—ฐ SQL ์ €์žฅ์†Œ์— ์Œ“์—ฌ์žˆ๋Š” Query๋“ค์„ DB๋กœ ๋‚ ๋ฆฐ๋‹ค. flush()

flush() ๋Š” 1์ฐจ์บ์‹œ๋ฅผ ์ง€์šฐ์ง€๋Š” ์•Š๋Š”๋‹ค. ์ฟผ๋ฆฌ๋“ค์„ DB์— ๋‚ ๋ ค์„œ DB์™€ ์‹ฑํฌ๋ฅผ ๋งž์ถ”๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.
7) flush() ํ›„์— ์‹ค์ œ DB์— ์ „๋‹ฌ๋˜๊ณ  Transaction์ด ์ปค๋ฐ‹๋œ๋‹ค. (commit())

 

๋ฌผ๋ก  flush๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ๋‹ค.

๋˜๋Š” JPQL์ด ์‹คํ–‰๋˜๋ฉด flush๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.

 

JPQL ์“ฐ๊ธฐ ์ฟผ๋ฆฌ๊ฐ€ ์‹คํ–‰๋˜๋ฉด ํ”Œ๋Ÿฌ์‹œ๊ฐ€ ๋ฌด์กฐ๊ฑด ํ˜ธ์ถœ๋œ๋‹ค๊ณ ์š”?

JPQL ์ฟผ๋ฆฌ ์‹คํ–‰์‹œ ํ”Œ๋Ÿฌ์‹œ๋ฅผ ์ž๋™ ํ˜ธ์ถœํ•œ๋‹ค. ์„ค๋ช…์— ๊ทธ๋ ‡๊ฒŒ ์ ํ˜€์žˆ๊ธดํ•˜๋‹ค.

em.persist(memberA);
em.persist(memberB);
em.persist(memberC);

//์ค‘๊ฐ„์— JPQL ์‹คํ–‰. ์œ„์— ์žˆ๋Š” A,B,C๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์ฟผ๋ฆฌ์— ๋ฐ˜์˜์ด ๋ ๊นŒ?
query = em.createQuery("select m from Member m", Member.class);
List<Member> members= query.getResultList();

๋‹จ์ˆœํ•œ select ๋ผ๋ฉด ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ์‹๋ณ„์ž๋ฅผ ํ†ตํ•ด ์บ์‹ฑ ํ•˜๋”๋ผ๋„ ์ •ํ•ฉ์„ฑ์ด ๊นจ์ง€์ง€ ์•Š๋Š”๋‹ค.

ํ•˜์ง€๋งŒ JPQL์€ ์ฟผ๋ฆฌ๋ฌธ, ์ฆ‰ ์–ด๋–ค ๊ฒฐ๊ณผ๋ฅผ ๊ฐ€์ ธ์˜ฌ์ง€ ์‹คํ–‰์ „์—๋Š” ์•Œ ์ˆ˜ ์—†๋‹ค. ์ฟผ๋ฆฌ๋ฌธ์˜ ์กฐ๊ฑด์— ๋”ฐ๋ผ ๊ฒฐ๊ณผ๊ฐ’์ด ๋‹ฌ๋ผ์ง€๋‹ˆ๊นŒ

๊ทธ๋ž˜์„œ JPQL ์‹คํ–‰์ „ flush๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ ์ด๋Ÿฌํ•œ ์˜ค๋ฅ˜๋ฅผ ๋ฐฉ์ง€ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

 

๐Ÿ˜’ : ๊ทธ๋Ÿผ ์‹๋ณ„์žID ๋ฅผ ํ†ตํ•œ ๋‹จ์ˆœ ์กฐํšŒ๋ฌธ( em.find() )๋„ JPQL๋กœ ์ž‘์„ฑํ•˜๋ฉด ๋ฌด์กฐ๊ฑด ๋จผ์ € ํ”Œ๋Ÿฌ์‹œ๊ฐ€ ๋˜๊ฒ ๋„ค์š”?

๋ฌด์กฐ๊ฑด์ด ์•„๋‹ˆ๋‹ค! ์ƒํ™ฉ์— ๋”ฐ๋ผ ๋‹ค๋ฅด๋‹ค.

โžก em.find()์™€ ๋˜‘๊ฐ™์€ ๋™์ž‘์„ ํ•˜๋Š” JPQL ์ฟผ๋ฆฌ๋ฌธ์„ ์ž‘์„ฑํ•œ ๊ฒฝ์šฐ #1 flush๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

์ •ํ•ฉ์„ฑ์„ ๊นจ๋œจ๋ฆฌ์ง€ ์•Š๊ธฐ ์œ„ํ•ด ์•ž์— ์Œ“์—ฌ์žˆ๋˜ ๊ธฐ์กด์˜ ์ž‘์—…๋“ค์ด flush ๋œ๋‹ค.

โžก em.find()์™€ ๋˜‘๊ฐ™์€ ๋™์ž‘์„ ํ•˜๋Š” JPQL ์ฟผ๋ฆฌ๋ฌธ์„ ์ž‘์„ฑํ•œ ๊ฒฝ์šฐ #2 flush๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.

๋†€๋ž๊ฒŒ๋„ flush๊ฐ€ ๋˜์ง€ ์•Š์€ ์ƒํƒœ๋กœ JPQL ์ฟผ๋ฆฌ๊ฐ€ ๋‚˜๊ฐ”๋‹ค. (* flush ์„ค์ • ๋ฐ”๊พผ๊ฑฐ ์—†์Œ)

 

Hibernate์—์„œ flush๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๋™์ž‘ํ•œ๋‹ค.

  • ํŠธ๋žœ์žญ์…˜์„ ์ปค๋ฐ‹ํ•˜๊ธฐ ์ „
  • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ ์“ฐ๊ธฐ ์ง€์—ฐ ์ €์žฅ์†Œ์— ๋Œ€๊ธฐ ์ค‘์ธ ์—”ํ„ฐํ‹ฐ์˜ ์ž‘์—…๊ณผ ๊ฒน์น˜๋Š” JPQL ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์ „
  • ๋„ค์ดํ‹ฐ๋ธŒ SQL ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์ „

์ฆ‰, ์—”ํ‹ฐํ‹ฐ ์ž‘์—…์ด ๊ฒน์น˜์ง€ ์•Š์œผ๋ฉด flush๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์•„๋ž˜์™€ ๊ฐ™์€ ์˜ˆ์ œ์—์„œ,

select a from Article a ๋Š” flush()๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์ง€๋งŒ

select m from Member a ๋Š” flush()๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ๋Œ€๊ธฐ์ค‘์ธ ์—”ํ„ฐํ‹ฐ ์ž‘์—…์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

Member์™€ ์ƒ๊ด€์—†๋Š” Article JPQL ์ฟผ๋ฆฌ๋Š”, flush๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.

 

์•„, ๊ทธ๋Ÿผ em.find()๋Š” ํ”Œ๋Ÿฌ์‹œ๊ฐ€ ๋˜์ง€ ์•Š์•„์„œ ์ •ํ•ฉ์„ฑ์ด ๊นจ์งˆ ์ˆ˜๋„ ์žˆ๊ฒ ๋„ค์š”?

์ด ์งˆ๋ฌธ์„ ์ดํ•ดํ•˜๋ ค๋ฉด SpringDataJPA์˜ repository.findById() ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์•„๋ž˜ ์˜ˆ์ œ๋ฅผ ๋ด์•ผํ•œ๋‹ค.

SpringDataJPA์˜ findById()๋Š” JPQL์„ ์‚ฌ์šฉํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๊ธฐ์—, flush๊ฐ€ ๋˜์ง€ ์•Š๋Š”๋‹ค.

 

๊ทธ๋ž˜์„œ ์œ„์˜ ์˜ˆ์ œ์ฒ˜๋Ÿผ 1์ฐจ ์บ์‹œ ์ •ํ•ฉ์„ฑ์„ ๊นจ๋œจ๋ ค๋ฒ„๋ฆด ์ˆ˜ ์žˆ๋‹ค.

  1. ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , save()๋ฅผ ํ•œ๋‹ค.
    @Id @GeneratedValue(IDENTITY) ๋ผ์„œ ํ‚ค ๊ฐ’์„ ์–ป๊ธฐ ์œ„ํ•ด DB insert ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค 
  2. ์ดํ›„ read()๋กœ ๊ฐ™์€ ๊ฐ์ฒด๋ฅผ ์ฝ์–ด์˜ค๊ณ , update()๋กœ ๊ฐ์ฒด๋ฅผ ์ˆ˜์ •ํ•œ๋‹ค.
    ์ด๋•Œ๋Š” DB ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค. ์‹๋ณ„์ž(ID)๋ฅผ ํ†ตํ•ด Persistence Context ๋‚ด์—์„œ๋งŒ ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์ €์žฅ๋œ๋‹ค.
  3. delete() ๋กœ ๊ฐ์ฒด๋ฅผ ์‚ญ์ œํ•œ๋‹ค.
    ์ด ์—ญ์‹œ DB ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค. ์‹๋ณ„์ž(ID)๋ฅผ ํ†ตํ•ด Persistence Context ๋‚ด์—์„œ๋งŒ ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์ €์žฅ๋œ๋‹ค.
  4. ์ดํ›„ ์ปค๋ฐ‹ํ•˜๊ธฐ ์ „์— findById()๋กœ ์‚ญ์ œํ•œ ๊ฐ์ฒด๋ฅผ ์กฐํšŒํ•œ๋‹ค.
    DB insert ์ฟผ๋ฆฌ๊ฐ€ ๋‚˜๊ฐ€๊ณ , ์•„์ง delete์ฟผ๋ฆฌ๊ฐ€ ๋‚˜๊ฐ€์ง€ ์•Š์•˜๋‹ค.
    ์ฆ‰ DB์—๋Š” insert๋œ ๊ฐ’์ด ๋‚จ์•„ ์žˆ์œผ๋ฏ€๋กœ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ์‚ญ์ œํ•œ ๊ฐ์ฒด๋ฅผ DB์—์„œ ์ž˜ ๊ฐ€์ ธ์˜จ๋‹ค.
    ์ดํ›„ ๊ฐ€์ ธ์˜จ ์—”ํ‹ฐํ‹ฐ(=์ด๋ฏธ deleted()๋œ ์—”ํ‹ฐํ‹ฐ)๋ฅผ ๋ณ€๊ฒฝํ•œ๋‹ค๋ฉด? ์ •ํ•ฉ์„ฑ์ด ๊นจ์กŒ๋‹ค!
  5. tx.commit() ์ดํ›„ DirtyChecking์„ ํ†ตํ•ด DB deleted ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
     

๊ณผ์—ฐ ๊ทธ๋Ÿด๊นŒ?

๋†€๋ž๊ฒŒ๋„, ์ •ํ•ฉ์„ฑ์ด ๊นจ์ง€์ง€ ์•Š์•˜๋‹ค.

1. DB insert ์ฟผ๋ฆฌ๊ฐ€ ๋‚˜๊ฐ”๊ณ  

2. delete() ์ž‘์—…์€ ์“ฐ๊ธฐ์ง€์—ฐ์ด ๋ฐœ๋™ํ•˜์—ฌ DB ์ฟผ๋ฆฌ๊ฐ€ ๋‚˜๊ฐ€์ง€ ์•Š์•˜๋‹ค.

์ฐธ๊ณ ๋กœ update๋Š” ์ฟผ๋ฆฌ๊ฐ€ ์•„์˜ˆ ์ฐํžˆ์ง€ ์•Š๋Š”๋‹ค. dirty-checking์„ ํ†ตํ•ด ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๋”๋ณด๊ธฐ
JPA ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ–ˆ๋‹ค๊ณ  ํ•ด๋„, ์—”ํ‹ฐํ‹ฐ์˜ ์ƒํ™ฉ์— ๋”ฐ๋ผ DB flush๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค.
em.flush() ํ•˜๋Š” ์‹œ์ ์— dirtyChecing์ด ์ผ์–ด๋‚œ๋‹ค.

 3. ๊ทธ ์ƒํƒœ์—์„œ tx.commit() ์ „์— ๋‹ค์‹œ DB select๋ฅผ ๋•Œ๋ ธ์œผ๋ฉด...์ •ํ•ฉ์„ฑ์ด ๊นจ์ง€๋ฉด์„œ ๊ฐ€์ ธ์™€์ ธ์•ผํ•˜๋Š”๋ฐ?

์ •์ƒ ์‚ญ์ œ๋˜์—ˆ๋‹ค. null์ด ๋ฐ˜ํ™˜๋˜์—ˆ๋‹ค. ์ •์ƒ ์‚ญ์ œ๋˜์—ˆ๋‹ค. ๊ทธ ์ดํ›„ ๋’ค๋Šฆ๊ฒŒ delete ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•˜์˜€๋‹ค..์ด๊ฒŒ ๋ฌด์Šจ?

 

์ •ํ•ฉ์„ฑ์ด ์ž˜ ์œ ์ง€๋˜์—ˆ๋‹ค. ์–ด๋–ป๊ฒŒ ์ด๊ฒŒ ๊ฐ€๋Šฅํ•œ๊ฑธ๊นŒ?

๋‹ต์€ ์‹๋ณ„์ž(ID)๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. JPA- hibernate ์ฟผ๋ฆฌ๋ฅผ ์ฐ์–ด๋ณด์ž

Entity is null ? : null ๋กœ๊ทธ ๋ฐ”๋กœ ์ด์ „์— ๋™์ž‘์„ ์‚ดํŽด๋ณด๋ฉด

DefaultLoadEventListener๋ฅผ ํ†ตํ•ด์„œ Loading Entity๋ฅผ ํ™•์ธํ•œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์„ค๋ช…๋„ ์นœ์ ˆํ•˜๊ฒŒ ์ ํ˜€์žˆ๋Š”๋ฐ

CacheEntityLoaderHelper : 
Load request found matching entity in context, but it is scheduled for removal; returning null.

PC์—์„œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ฐพ์•˜์ง€๋งŒ, ํ•ด๋‹น ์—”ํ‹ฐํ‹ฐ๊ฐ€ remove ์ƒํƒœ๋กœ ์˜ˆ์•ฝ๋˜์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ์— null์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

๋‹ค์Œ ๊ธ€์˜ ์„ค๋ช… ์„ ๋นŒ๋ ค์˜ค์ž๋ฉด ์—”ํ‹ฐํ‹ฐ ์ƒํƒœ ์ „ํ™˜ ์ž‘์—…์€ ํŠธ๋žœ์žญ์…˜ ์ปค๋ฐ‹์‹œ์— ๋ฐ˜์˜๋˜๋ฉฐ, ์กฐ๊ธฐ์— flush๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์ƒํƒœ ์ „ํ™˜์ž‘์—…์€ ํŠธ๋žœ์žญ์…˜ ๋งˆ์ง€๋ง‰์—(์กฐํšŒ ์ž‘์—…๊ณผ ์•ˆ๊ฒน์น˜๊ฒŒ)์‚ฌ์šฉํ•˜๋ผ๊ณ  ๊ถŒ์žฅ ํ•œ๋‹ค.

 

ํ•˜์ด๋ฒ„๋„ค์ดํŠธ flush ๋ชจ๋“œ๋ฅผ ์„ค์ •ํ• ๋•Œ, AUTO๋ผ๊ณ  ์ ์€ ์ด์œ ๋ฅผ ์ด์ œ ์กฐ๊ธˆ ์•Œ ๊ฒƒ๊ฐ™๊ธฐ๋„ ํ•˜๋‹ค.

 

๐Ÿ˜ : ๊ทธ๋Ÿผ ์‹๋ณ„์ž(ID)๊ฐ€ ์•„๋‹Œ ๋‹ค๋ฅธ ๊ฐ’์œผ๋กœ ์กฐํšŒํ•˜๋ฉด ์ •ํ•ฉ์„ฑ์ด ๊นจ์ง€๊ฒ ๋„ค์š”?

๊ทธ๋ ‡๋‹ค. ๊นจ์ง„๋‹ค. ๊ทผ๋ฐ ID๊ฐ€ ์•„๋‹Œ ๋‹ค๋ฅธ ๊ฐ’์œผ๋กœ ์กฐํšŒ == JPQL์˜ ์‚ฌ์šฉ์ด๋ผ์„œ ์œ„์—์„œ ์ ์ ˆํ•˜๊ฒŒ flush๊ฐ€ ๋™์ž‘ํ•œ๋‹ค. 

 

๋‹น์—ฐํžˆ em.setFlushMode(FlushModeType.COMMIT) ์œผ๋กœ JPQL ์ž‘์—…์ด flush๊ฐ€ ๋™์ž‘ํ•˜์ง€ ์•Š๋„๋ก ๊ฐ•์ œ๋กœ ์„ค์ •ํ•œ๋‹ค๋ฉด ์ •ํ•ฉ์„ฑ์ด ๊นจ์ง„๋‹ค.

 

๋˜ํ•œ ์˜ˆ์ œ์—์„œ ๋‚˜์˜จ ์ž‘์—…์„ JPA๋ฅผ ๊ฑฐ์น˜์ง€ ์•Š๊ณ  ๋˜‘๊ฐ™์ด ํ•œ๋‹ค๋ฉด ๋‹น์—ฐํžˆ ์ •ํ•ฉ์„ฑ์ด ๊นจ์ง„๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์•„๋ž˜์ฒ˜๋Ÿผ jdbcTemplate์œผ๋กœ ์ง์ ‘ ์ฟผ๋ฆฌ๋ฅผ ์ฐ๋Š”๋‹ค๊ฑฐ๋‚˜.

actual = jdbcTemplate.queryForObject("SELECT * FROM member where id = ?", (rs, rowNum) -> {
    Member dbMember = new Member();
    dbMember.setId(rs.getLong("id"));
    dbMember.setUsername(rs.getString("username"));
    return dbMember;
}, member.getId());

 

@Modify ์ž‘์„ฑ์˜ˆ์ •-

๋ธ”๋กœ๊ทธ์˜ ์ •๋ณด

JiwonDev

JiwonDev

ํ™œ๋™ํ•˜๊ธฐ