๋ JPA๋ฅผ ์ ๋๋ก ์๊ณ ์ฐ๋ ๊ฒ์ธ๊ฐ (์ ๋ฆฌ์ค..)
by JiwonDev# ๋ ํผ๋ฐ์ค
https://msolo021015.medium.com/jpa-persistence-context-deep-dive-2f36f9bd6214
#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๊ฐ ๋ฐ์ํ๋ค.
โก em.find()์ ๋๊ฐ์ ๋์์ ํ๋ JPQL ์ฟผ๋ฆฌ๋ฌธ์ ์์ฑํ ๊ฒฝ์ฐ #2 flush๊ฐ ๋ฐ์ํ์ง ์๋๋ค.
Hibernate์์ flush๋ ์๋์ ๊ฐ์ด ๋์ํ๋ค.
- ํธ๋์ญ์ ์ ์ปค๋ฐํ๊ธฐ ์
- ์์์ฑ ์ปจํ ์คํธ์ ์ฐ๊ธฐ ์ง์ฐ ์ ์ฅ์์ ๋๊ธฐ ์ค์ธ ์ํฐํฐ์ ์์ ๊ณผ ๊ฒน์น๋ JPQL ์ฟผ๋ฆฌ๋ฅผ ์คํํ๊ธฐ ์
- ๋ค์ดํฐ๋ธ SQL ์ฟผ๋ฆฌ๋ฅผ ์คํํ๊ธฐ ์
์ฆ, ์ํฐํฐ ์์ ์ด ๊ฒน์น์ง ์์ผ๋ฉด flush๊ฐ ๋ฐ์ํ์ง ์๋๋ค.
์๋ฅผ ๋ค์ด ์๋์ ๊ฐ์ ์์ ์์,
select a from Article a ๋ flush()๊ฐ ๋ฐ์ํ์ง ์์ง๋ง
select m from Member a ๋ flush()๊ฐ ๋ฐ์ํ๋ค. ์์์ฑ ์ปจํ ์คํธ์ ๋๊ธฐ์ค์ธ ์ํฐํฐ ์์ ์ด ์๊ธฐ ๋๋ฌธ์ด๋ค.
์, ๊ทธ๋ผ em.find()๋ ํ๋ฌ์๊ฐ ๋์ง ์์์ ์ ํฉ์ฑ์ด ๊นจ์ง ์๋ ์๊ฒ ๋ค์?
์ด ์ง๋ฌธ์ ์ดํดํ๋ ค๋ฉด SpringDataJPA์ repository.findById() ๋ฅผ ์ฌ์ฉํ๋ ์๋ ์์ ๋ฅผ ๋ด์ผํ๋ค.
SpringDataJPA์ findById()๋ JPQL์ ์ฌ์ฉํ๋๊ฒ ์๋๊ธฐ์, flush๊ฐ ๋์ง ์๋๋ค.
๊ทธ๋์ ์์ ์์ ์ฒ๋ผ 1์ฐจ ์บ์ ์ ํฉ์ฑ์ ๊นจ๋จ๋ ค๋ฒ๋ฆด ์ ์๋ค.
- ์ํฐํฐ๋ฅผ ์์ฑํ๊ณ , save()๋ฅผ ํ๋ค.
@Id @GeneratedValue(IDENTITY) ๋ผ์ ํค ๊ฐ์ ์ป๊ธฐ ์ํด DB insert ์ฟผ๋ฆฌ๊ฐ ๋ฐ์ํ๋ค - ์ดํ read()๋ก ๊ฐ์ ๊ฐ์ฒด๋ฅผ ์ฝ์ด์ค๊ณ , update()๋ก ๊ฐ์ฒด๋ฅผ ์์ ํ๋ค.
์ด๋๋ DB ์ฟผ๋ฆฌ๊ฐ ๋ฐ์ํ์ง ์๋๋ค. ์๋ณ์(ID)๋ฅผ ํตํด Persistence Context ๋ด์์๋ง ๋ณ๊ฒฝ์ฌํญ์ด ์ ์ฅ๋๋ค. - delete() ๋ก ๊ฐ์ฒด๋ฅผ ์ญ์ ํ๋ค.
์ด ์ญ์ DB ์ฟผ๋ฆฌ๊ฐ ๋ฐ์ํ์ง ์๋๋ค. ์๋ณ์(ID)๋ฅผ ํตํด Persistence Context ๋ด์์๋ง ๋ณ๊ฒฝ์ฌํญ์ด ์ ์ฅ๋๋ค. - ์ดํ ์ปค๋ฐํ๊ธฐ ์ ์ findById()๋ก ์ญ์ ํ ๊ฐ์ฒด๋ฅผ ์กฐํํ๋ค.
DB insert ์ฟผ๋ฆฌ๊ฐ ๋๊ฐ๊ณ , ์์ง delete์ฟผ๋ฆฌ๊ฐ ๋๊ฐ์ง ์์๋ค.
์ฆ DB์๋ insert๋ ๊ฐ์ด ๋จ์ ์์ผ๋ฏ๋ก ์์์ฑ ์ปจํ ์คํธ์์ ์ญ์ ํ ๊ฐ์ฒด๋ฅผ DB์์ ์ ๊ฐ์ ธ์จ๋ค.
์ดํ ๊ฐ์ ธ์จ ์ํฐํฐ(=์ด๋ฏธ deleted()๋ ์ํฐํฐ)๋ฅผ ๋ณ๊ฒฝํ๋ค๋ฉด? ์ ํฉ์ฑ์ด ๊นจ์ก๋ค! - tx.commit() ์ดํ DirtyChecking์ ํตํด DB deleted ์ฟผ๋ฆฌ๊ฐ ๋ฐ์ํ๋ค.
๊ณผ์ฐ ๊ทธ๋ด๊น?
๋๋๊ฒ๋, ์ ํฉ์ฑ์ด ๊นจ์ง์ง ์์๋ค.
1. DB insert ์ฟผ๋ฆฌ๊ฐ ๋๊ฐ๊ณ
2. delete() ์์ ์ ์ฐ๊ธฐ์ง์ฐ์ด ๋ฐ๋ํ์ฌ DB ์ฟผ๋ฆฌ๊ฐ ๋๊ฐ์ง ์์๋ค.
์ฐธ๊ณ ๋ก update๋ ์ฟผ๋ฆฌ๊ฐ ์์ ์ฐํ์ง ์๋๋ค. dirty-checking์ ํตํด ์ฟผ๋ฆฌ๋ฅผ ์์ฑํ๊ธฐ ๋๋ฌธ์ด๋ค.
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 ์์ฑ์์ -
'๐ฑBackend > Java' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
DTO๋ ์ด๋ค Layer์ ํฌํจ๋์ด์ผ ํ๋๊ฐ. (1) | 2022.01.21 |
---|---|
Mapstruct(DTO Mapper ๋ผ์ด๋ธ๋ฌ๋ฆฌ) (0) | 2022.01.20 |
ํ ์คํธ ๋ชจํน Mockito ๋ผ์ด๋ธ๋ฌ๋ฆฌ (0) | 2021.09.07 |
[์ฝ๋๋ถ์๋๊ตฌ]# 3 SonarLint, SonarQube (0) | 2021.08.21 |
[์ฝ๋๋ถ์๋๊ตฌ]#2 Jacoco ์ ์ฉํ๊ธฐ (0) | 2021.08.21 |
๋ธ๋ก๊ทธ์ ์ ๋ณด
JiwonDev
JiwonDev