Persistence Context
JPA μμ κ°μ₯ μ€μν 2κ°μ§
JPA λ₯Ό μ¬μ©νλ©΄μ κ°μ₯ μ€μν κ²μ βκ°μ²΄μ RDB μ΄λ»κ² 맀νν κ²μΈκ°β μ΄λ€. μ¦, κ°μ²΄μ DB λ₯Ό μ΄λ»κ² μ€κ³ν κ²μΈμ§μ λν μ μ μΈ κ΄μ μ μ΄ν΄νκΈ° μν΄ Object Relational Mapping μ λν΄ μ΄ν΄νλ κ²μ΄ μ€μνλ€. κ·Έλ¦¬κ³ , μ€μ JPA κ° λ΄λΆμ μΌλ‘ μ΄λ»κ² λμνλμ§ μ΄ν΄νκΈ° μν΄ μμμ± μ»¨ν μ€νΈμ λν΄ μ΄ν΄ν΄μΌ νλ€.
μν°ν° 맀λμ ν©ν 리μ μν°ν° 맀λμ
μμμ± μ»¨ν μ€νΈκ° λμΌ?
μμμ± μ»¨ν
μ€νΈλ μν°ν°λ₯Ό μꡬ μ μ₯νλ νκ²½μ΄λΌκ³ μκ°ν μ μμΌλ©°, JPA λ₯Ό μ΄ν΄νλλ° κ°μ₯ μ€μν μ©μ΄μ΄λ€.
EntityManager.persist(entity);
νΈμΆμ λ¨μν DB μ μ μ₯νλ κ²μ΄ μλ, μν°ν°λ₯Ό μμμ± μ»¨ν
μ€νΈλΌλ κ³³μ μ μ₯νκ² λ€λ μλ―Έλ₯Ό κ°μ§κ³ μλ€.
μν°ν° 맀λμ ? μμμ± μ»¨ν μ€νΈ?
μμμ± μ»¨ν μ€νΈλ λ Όλ¦¬μ μΈ κ°λ μΌλ‘ λμ 보μ΄μ§ μλλ€. JPA λ₯Ό μ¬μ©νλ κ²μ μν°ν° 맀λμ λ₯Ό ν΅ν΄μ μμμ± μ»¨ν μ€νΈμ μ κ·Όνλ κ²μ΄λΌκ³ μκ°ν μ μλ€.
μν°ν°μ μλͺ μ£ΌκΈ°
μν°ν°μ μλͺ
μ£ΌκΈ°λ μ΄ 4κ°μ§λ‘ λΆλ₯λ μ μλ€.
- λΉμμ(new/transient) μνλ μμμ± μ»¨ν μ€νΈμ μ ν κ΄κ³κ° μλ μλ‘μ΄ μνλ₯Ό μλ―Έ
- μμ(managed) μνλ μμμ± μ»¨ν μ€νΈμ μν΄ κ΄λ¦¬λλ μνλ₯Ό μλ―Έ
- μ€μμ(detached) μνλ μμμ± μ»¨ν μ€νΈμ μ μ₯λμλ€κ° λΆλ¦¬λ μνλ₯Ό μλ―Έ
- μμ (removed) μνλ μμ λ μνλ₯Ό μλ―Έ
λΉμμ
// κ°μ²΄λ₯Ό μμ±ν μν(λΉμμ)
Member member = new Member();
member.setId("member1");
member.setUsername("νμ1");
μμ
// κ°μ²΄λ₯Ό μμ±ν μν(λΉμμ)
Member member = new Member();
member.setId("member1");
member.setUsername("νμ1");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
// κ°μ²΄λ₯Ό μ μ₯ν μν(μμ)
em.persist(member);
μ€μμ, μμ
// νμ μν°ν°λ₯Ό μμμ± μ»¨ν
μ€νΈμμ λΆλ¦¬, μ€μμ μν
em.detach(member);
// κ°μ²΄λ₯Ό μμ ν μν(μμ )
em.remove(member);
μμμ± μ»¨ν μ€νΈμ μ΄μ
- 1μ°¨ μΊμ
- 1μ°¨ μΊμμμ μ‘°νκ° κ°λ₯νλ©° 1μ°¨ μΊμμ μλ€λ©΄ DB μμ μ‘°ννμ¬ 1μ°¨ μΊμμ μ¬λ € λλλ€.
- λμΌμ±(Identity) 보μ₯
- λμΌμ± λΉκ΅λ₯Ό 보μ₯νλ€.
- νΈλμμ
μ μ§μνλ μ°κΈ° μ§μ°(Transactional Write-Behind)
- νΈλμμ μ μ§μνλ μ°κΈ° μ§μ°μ΄ κ°λ₯νλ©° νΈλμμ 컀λ°νκΈ° μ κΉμ§ 쿼리λ₯Ό λ°λ‘ 보λ΄μ§ μκ³ λͺ¨μμ λ³΄λΌ μ μλ€.
- λ³κ²½ κ°μ§(Dirty Checking)
- 1μ°¨ μΊμμ λ€μ΄μ¨ λ°μ΄ν°μ μ€λ μ·μ μ°μ΄λμ΄ μ»€λ° μμ μ μν°ν°μ μ€λ μ·μ λΉκ΅νμ¬ UPDATE 쿼리λ₯Ό μμ±νλ€.
- μ§μ° λ‘λ©(Lazy Loading)
- μν°ν°μμ ν΄λΉ μν°ν°λ₯Ό λΆλ¬μ¬ λ 쿼리λ₯Ό λ λ € ν΄λΉ λ°μ΄ν°λ₯Ό κ°μ Έμ¨λ€.
μν°ν° μ‘°ν, 1μ°¨ μΊμ
// μν°ν°λ₯Ό μμ±ν μν(λΉμμ)
Member member = new Member();
member.setId("member1");
member.setUsername("νμ1");
// μν°ν°λ₯Ό μμ, 1μ°¨ μΊμμ μ μ₯λ€
em.persist(member);
// 1μ°¨ μΊμμμ μ‘°ν
Member findMember = em.find(Member.class, "member1");
// DB μμ μ‘°ν
Member findMember2 = em.find(Member.class, "member2");
λΉμ§λμ€κ° λλλ²λ¦¬λ©΄ μμμ± μ»¨ν μ€νΈλ₯Ό μ§μλ²λ¦¬κΈ° λλ¬Έμ, 1μ°¨ μΊμλ λ€ λ λΌκ°μ μ¬μ€ μ±λ₯μ ν° λμμ΄ λμ§λ μλλ€. μ¦, ν νΈλμμ μμμλ§ μ΄μ μ΄ μλ€.
μμ μν°ν°μ λμΌμ± 보μ₯
Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");
System.out.println(a == b); // λμΌμ± λΉκ΅ true
μν°ν° λ±λ‘ μ νΈλμμ μ μ§μνλ μ°κΈ° μ§μ°
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
// μν°ν° 맀λμ λ λ°μ΄ν° λ³κ²½μ νΈλμμ
μ μμν΄μΌ νλ€.
transaction.begin(); // [νΈλμμ
] μμ
em.persist(memberA);
em.persist(memberB);
// μ¬κΈ°κΉμ§ INSERT SQLμ λ°μ΄ν°λ² μ΄μ€μ 보λ΄μ§ μλλ€.
// 컀λ°νλ μκ° λ°μ΄ν°λ² μ΄μ€μ INSERT SQLμ 보λΈλ€.
transaction.commit(); // [νΈλμμ
] 컀λ°
memberA
κ° 1μ°¨ μΊμμ λ€μ΄κ°κ³ INSERT SQL λ§λ€μ΄μ μ°κΈ° μ§μ° SQL μ μ₯μμ λ£μ΄λλ€.
memberB
κ° 1μ°¨ μΊμμ λ€μ΄κ°κ³ INSERT SQL λ§λ€μ΄μ μ°κΈ° μ§μ° SQL μ μ₯μμ λ£μ΄λλ€.
컀λ°λλ μμ μ
flush
ν commit
μ μ§ννλ€.
μ΄λ JDBC Batch μ κ°μ μν μ νκ³ μλ€.
Hibernate μλ size λ§νΌ λͺ¨μμ νλ°©μ DB μ 컀λ°νλ μ΅μ
μ΄ μ‘΄μ¬νκΈ°λ νλ€.
μν°ν° μμ λ³κ²½ κ°μ§
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin(); // [νΈλμμ
] μμ
// μμ μν°ν° μ‘°ν
Member memberA = em.find(Member.class, "memberA");
// μμ μν°ν° λ°μ΄ν° μμ
memberA.setUsername("hi");
memberA.setAge(10);
// em.update(member) μ΄λ° μ½λκ° μμ΄μΌ νμ§ μμκΉ?
transaction.commit(); // [νΈλμμ
] 컀λ°
μμμ± μ»¨ν μ€νΈκ° μν°ν°λ₯Ό κ΄λ¦¬νκ³ μκΈ° λλ¬Έμ λ³κ²½μ κ°μ§ν μ μλ€. λ³κ²½μ¬νμ΄ μμΌλ©΄ μ»€λ° μκ°μ UPDATE 쿼리λ₯Ό λ§λ€μ΄μ λ λ¦°λ€.
μ΄λ»κ² λ³κ²½μ¬νμ κ°μ§νλ κ±ΈκΉ?
1μ°¨ μΊμμλ μ€λ
μ·μ΄λΌλ 곡κ°μ΄ μλ€. κ°μ΄ 1μ°¨ μΊμμ λ€μ΄μ¨ μ΅μ΄ μμ μ μ€λ
μ·μ μ°μ΄λλλ€.
νΈλμμ
μ΄ μ»€λ°λλ μμ μ JPA κ° μν°ν°μ μ€λ
μ·μ λΉκ΅νμ¬ λ³κ²½ μ¬νμ΄ μ‘΄μ¬ν κ²½μ° UPDATE SQL μμ± ν 컀λ°μ μ§ννλ€.
μν°ν° μμ
// μμ λμ μν°ν° μ‘°ν
Member memberA = em.find(Member.class, βmemberA");
em.remove(memberA); // μν°ν° μμ
νλ¬μ
νλ¬μλ μμμ± μ»¨ν μ€νΈμ λ³κ²½λ΄μ©μ DB μ λ°μνλ€λ μλ―Έμ΄λ€. νμ§λ§, νΈλμμ μ΄ μΌμ΄λκΈ° μ μλ DB μ μ€μ λ‘ λ°μλμ§ μλλ€. μ¦, νλ¬μλ DB μ λκΈ°νλ₯Ό νλ κ³Όμ μ΄λΌκ³ μκ°ν μ μμΌλ©°, μ»€λ° μμ μ μ€μ λ‘ DB μ λ°μλλ€.
νλ¬μ λ°μ
νλ¬μλ DB νΈλμμ μ΄ μ»€λ°λ λ μλμ μΌλ‘ λ°μνλ€. μ΄λ μμμ± μ»¨ν μ€νΈμ κΈ°λ₯ μ€ νλμΈ λ³κ²½ κ°μ§λ₯Ό ν΅ν΄ μμ λ μν°ν°μ μ 보λ₯Ό μ°κΈ° μ§μ° SQL μ μ₯μμ μ μ₯ν΄λλ€. μ΄ν, νλμκ° λ°μνλ©΄ μ°κΈ° μ§μ° SQL μ μ₯μμ 쿼리λ₯Ό DB μ μ μ‘
μμμ± μ»¨ν μ€νΈλ₯Ό νλ¬μνλ λ°©λ²
μμμ± μ»¨ν μ€νΈλ₯Ό νλ¬μνλ λ°©λ²μ μ΄ 3κ°μ§κ° μ‘΄μ¬νλ€.
em.flush()
λ₯Ό ν΅ν μ§μ νΈμΆ (κ±°μ μ¬μ©νμ§ μμ)- νΈλμμ 컀λ°μ ν΅ν μλ νΈμΆ
- JPQL 쿼리 μ€νμ ν΅ν μλ νΈμΆ νλ¬μλ₯Ό νλ©΄ 1μ°¨ μΊμκ° μ§μμ§λ κ²μ μλκ³ , μ°κΈ° μ§μ° SQL μ μ₯μμ μλ μΏΌλ¦¬κ° DB μ λκΈ°νλλ€λ μλ―Έλ‘ μκ°ν μ μλ€.
JPQL 쿼리 μ€ν μ νλ¬μκ° μλμΌλ‘ νΈμΆλλ μ΄μ
em.persist(memberA);
em.persist(memberB);
em.persist(memberC);
// μ€κ°μ JPQL μ€ν
query = em.createQuery("select m from Member m", Member.class);
List<Member> members= query.getResultList();
μμμ± μ»¨ν μ€νΈμ μλ λ°μ΄ν°λ₯Ό JPQL μΏΌλ¦¬λ‘ μ‘°ννλ €κ³ νλ©΄ DB μ μκΈ° λλ¬Έμ λ¬Έμ κ° λ μ μλ€. κ·Έλμ JPQL 쿼리 μ€ν μ μλμΌλ‘ νλ¬μ λλλ‘ μ€μ λμ΄ μλ€.
νλ¬μ λͺ¨λ μ΅μ
em.setFlushMode(FlushModeType.AUTO);
// 컀λ°μ΄λ 쿼리λ₯Ό μ€νν λ νλ¬μ (κΈ°λ³Έκ°)
em.setFlushMode(FlushModeType.COMMIT);
// 컀λ°ν λλ§ νλ¬μ, ν¬κ² λμμ΄ λμ§ μμ, κ·Έλ₯ μ€ν λ₯Ό μ°λ κ²μ΄ μ’μ
νλ¬μλ μμμ± μ»¨ν μ€νΈμ λ³κ²½λ΄μ©μ DB μ λκΈ°ννλ κ²μΌ λΏ, μμμ± μ»¨ν μ€νΈλ₯Ό λΉμ°μ§ μλλ€. νΈλμμ μ΄λΌλ μμ λ¨μκ° μ€μνκΈ° λλ¬Έμ, μ»€λ° μ§μ μλ§ νλ¬μλ₯Ό ν΅ν΄ λκΈ°ν ν΄μ£Όλ©΄ λλ€.
μ€μμ μν
μ€μμ μνλ, μμ μνμ μν°ν°κ° μμμ± μ»¨ν
μ€νΈμμ λΆλ¦¬(detached)λλ κ²μ μλ―Ένλ€.
μ€μμ μνκ° λ μν°ν°λ μμμ± μ»¨ν
μ€νΈκ° μ 곡νλ Dirty-Checking κ³Ό κ°μ κΈ°λ₯μ μ¬μ©νμ§ λͺ»νλ€.
em.persist()
λ em.find()
λ₯Ό μ¬μ©νλ©΄ μν°ν°κ° μμ μνλ‘ μμμ± μ»¨ν
μ€νΈμ λ±λ‘λλ€.
μ€μμ μνλ‘ λ§λλ λ°©λ²
em.detach(entity);
λ₯Ό ν΅ν΄ νΉμ μν°ν°λ§ μ€μμ μνλ‘ μ νem.clear();
λ₯Ό ν΅ν΄ μμμ± μ»¨ν μ€νΈλ₯Ό μμ ν μ΄κΈ°νem.close();
λ₯Ό ν΅ν΄ μμμ± μ»¨ν μ€νΈλ₯Ό μ’ λ£