JPA μ‹œμž‘

JPA(Java Persistnce API) λž€ μžλ°” μ§„μ˜μ—μ„œ ORM(Object-Relational Mapping) 기술 ν‘œμ€€μœΌλ‘œ μ‚¬μš©λ˜λŠ” μΈν„°νŽ˜μ΄μŠ€μ˜ λͺ¨μŒμ΄λ‹€. μžλ°” μ• ν”Œλ¦¬μΌ€μ΄μ…˜κ³Ό DB μ‚¬μ΄μ—μ„œ λ™μž‘ν•˜λ©°, SQL에 μ˜μ‘΄μ μ΄μ—ˆλ˜ κΈ°μ‘΄ λ°©μ‹μ˜ 단점을 κ·Ήλ³΅ν•˜κΈ° μœ„ν•΄ 데이터λ₯Ό 객체 지ν–₯ κ΄€μ μœΌλ‘œ 바라보고 λ‹€λ£° 수 있게 λ§Œλ“€μ–΄μ‘Œλ‹€.

🧩 ORM ?

  • κΈ°μ‘΄ λ°©μ‹μœΌλ‘œ 객체와 λ°μ΄ν„°λ² μ΄μŠ€λ₯Ό 관리할 λ•Œμ˜ λ¬Έμ œμ μ€ ν…Œμ΄λΈ”μ— λ§žμΆ°μ„œ 객체λ₯Ό λ§Œλ“€κ³ , 데이터λ₯Ό CRUDν•  λ•Œλ§ˆλ‹€ μˆ˜λ§Žμ€ 쿼리λ₯Ό μž‘μ„±ν•΄μ•Ό ν•œλ‹€λŠ” λ³΅μž‘ν•¨μ΄ μžˆμ—ˆλ‹€.

  • λ§Œμ•½ μžλ°” μ»¬λ ‰μ…˜μ— μ €μž₯ν•˜λ“―μ΄ CRUD μž‘μ—…μ„ ν•  수 μžˆλ‹€λ©΄ 훨씬 κ°„νŽΈν•œ 개발이 κ°€λŠ₯ν•΄μ§ˆ 것이닀.

  • κ°μ²΄λŠ” κ°μ²΄λŒ€λ‘œ μ„€κ³„ν•˜κ³ , κ΄€κ³„ν˜• λ°μ΄ν„°λ² μ΄μŠ€λŠ” κ΄€κ³„ν˜• λ°μ΄ν„°λ² μ΄μŠ€λŒ€λ‘œ μ„€κ³„ν•˜κ³ , ORM ν”„λ ˆμž„μ›Œν¬λŠ” μ€‘κ°„μ—μ„œ κ·Έ λ‘˜μ„ λ§€ν•‘ν•΄μ£ΌλŠ” 역할을 ν•œλ‹€.

  • JPA λŠ” μžλ°” μ§„μ˜μ—μ„œ ORM 역할을 λ‹΄λ‹Ήν•˜λŠ” μΈν„°νŽ˜μ΄μŠ€μ΄λ©°, ν•˜μ΄λ²„λ„€μ΄νŠΈ(Hibernate)κ°€ κ΅¬ν˜„μ²΄λ‘œμ„œ JPA의 ν‘œμ€€ λͺ…μ„Έλ₯Ό κ΅¬ν˜„ν•˜κ³  μžˆλ‹€.

🧩 JPA와 CRUD

  • JPA λŠ” μžλ°” μ»¬λ ‰μ…˜μ— 데이터λ₯Ό μ €μž₯ν•˜λ“―μ΄ (마치 list.add() 둜 μ €μž₯ν•˜λ“―μ΄) CRUD λ©”μ„œλ“œλ₯Ό μ œκ³΅ν•œλ‹€.
CRUDλ©”μ„œλ“œ
Cjpa.persist(member)
RMember member = jpa.find(memberId)
Umember.setName(β€œλ³€κ²½ν•  이름”)
Djpa.remove(member)

🧩 μ„±λŠ₯ μ΅œμ ν™” κΈ°λŠ₯

  • JPA λŠ” 같은 νŠΈλžœμž­μ…˜ μ•ˆμ—μ„œ 같은 μ—”ν‹°ν‹°λ₯Ό λ°˜ν™˜ν•œλ‹€. (μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ—μ„œ 1μ°¨ μΊμ‹œλ‘œ κ΄€λ¦¬ν•˜λ©°, 동일성을 보μž₯ν•œλ‹€)

  • μ“°κΈ° 지연 : νŠΈλžœμž­μ…˜μ„ 컀밋할 λ•Œ κΉŒμ§€ SQL 쿼리문을 λͺ¨μ•„λ’€λ‹€κ°€ μ»€λ°‹ν•˜λŠ” μˆœκ°„ ν•œλ²ˆμ— μ „μ†‘ν•œλ‹€.

  • 지연 λ‘œλ”©κ³Ό μ¦‰μ‹œ λ‘œλ”© : 지연 λ‘œλ”©μ΄λž€ 객체가 μ‹€μ œ μ‚¬μš©λ  λ•Œ 쿼리문을 μ‹€ν–‰ν•˜μ—¬ λ‘œλ”©ν•˜λŠ” 것을 λ§ν•˜λ©°, μ¦‰μ‹œ λ‘œλ”©μ€ Join SQL둜 ν•œλ²ˆμ— μ—°κ΄€λœ κ°μ²΄κΉŒμ§€ 미리 μ‘°νšŒν•΄λ‘λŠ” 것을 λ§ν•œλ‹€.

πŸ₯ μ½”λ“œλ‘œ μ΄ν•΄ν•΄λ³΄μž

package org.example;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

public class Main {
    public static void main(String[] args) {
        // EntityManagerFactory : μ• ν”Œλ¦¬μΌ€μ΄μ…˜ λ‘œλ”© μ‹œμ μ— λ”± ν•œλ²ˆ 생성.
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");

        // EntityManager : νŠΈλžœμž­μ…˜μ„ ν•˜λ‚˜ μ‹€ν–‰ν•  λ•Œ λ§ˆλ‹€ μƒμ„±ν•΄μ„œ μ‚¬μš©ν•˜κ³  버린닀. μ“°λ ˆλ“œκ°„μ— κ³΅μœ ν•˜λ©΄ μ•ˆ 됨.
        EntityManager em = emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        tx.begin();

        /**
         * JPA의 λͺ¨λ“  데이터 변경은 νŠΈλžœμž­μ…˜ μ•ˆμ—μ„œ μ‹€ν–‰ν•΄μ•Ό ν•œλ‹€. 변경이 λλ‚˜λ©΄ λ°˜λ“œμ‹œ em.close() 둜 μ’…λ£Œν•΄μ•Ό ν•œλ‹€.
         */
        try {
            /**
             * (C)
             * λΉ„μ˜μ† μƒνƒœ.
             */
           Member member = new Member();
           member.setId(1L);
           member.setName("Hello JPA");

            /**
             * μ˜μ† μƒνƒœ.
             * persist ν•΄μ•Ό JPA μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ μ•ˆμ— member 객체가 듀어감.
             * μ»¨ν…μŠ€νŠΈ μ•ˆμ—μ„œ 1μ°¨ μΊμ‹œλ‘œ μ €μž₯됨. (ν‚€ : db pk , κ°’ : entity 객체)
             */
           em.persist(member);

            /**
             * (R)
             * find ν•˜λ©΄ JPAλŠ” λ””λΉ„λ₯Ό μ‘°νšŒν•˜λŠ”κ²Œ μ•„λ‹Œ μ»¨ν…μŠ€νŠΈμ˜ 1μ°¨ μΊμ‹œλ₯Ό λ¨Όμ € μ‘°νšŒν•¨.
             * λ§Œμ•½ 1μ°¨ μΊμ‹œμ— μ—†λ‹€λ©΄ κ·Έμ œμ•Ό λ””λΉ„λ₯Ό μ‘°νšŒν•˜κ³ , μ‘°νšŒν•œ 값을 1μ°¨ μΊμ‹œμ— μ €μž₯ ν›„ κ·Έ 값을 λ°˜ν™˜ν•œλ‹€.
             */
           Member findMember = em.find(Member.class, 2L);

            /**
             * JPQL : 쿼리λ₯Ό 직접 μž‘μ„±ν•  μˆ˜λ„ μžˆλ‹€.
             * μ€‘μš”ν•œ 점은 λ””λΉ„ ν…Œμ΄λΈ”μ΄ μ•„λ‹Œ μ—”ν‹°ν‹° 객체λ₯Ό λŒ€μƒμœΌλ‘œ 쿼리λ₯Ό μ§ λ‹€λŠ” 점이닀.
             * μ•„λž˜ μ½”λ“œμ—μ„œ Member λŠ” ν…Œμ΄λΈ”μ΄ μ•„λ‹Œ μžλ°” ν΄λž˜μŠ€μ΄λ‹€. (νŒŒλΌλ―Έν„°λ‘œ Member.class λ₯Ό λͺ…μ‹œν•¨)
             */
           List<Member> result = em.createQuery("select m from Member as m", Member.class)
                   .setFirstResult(0)
                   .setMaxResults(10)
                   .getResultList();
           for (Member member : result) {
               System.out.println("member : " + member.getName());
           }

            /**
             * (U)
             * JPA의 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ μ•ˆμ— μžˆλŠ” κ°μ²΄λŠ” JPAκ°€ ν•΄λ‹Ή μ—”ν‹°ν‹°λ₯Ό κ΄€λ¦¬ν•˜κ³  μžˆλ‹€κ³  μƒκ°ν•˜λ©΄ λœλ‹€.
             * λ•Œλ¬Έμ— 변경이 λ°œμƒν•˜λ©΄ λ°”λ‘œ(μžλ™μœΌλ‘œ) DB에 λ°˜μ˜ν•œλ‹€.
             */
           findMember.setName("Bye JPA");

            /**
             * (D)
             */
           em.remove(findMember);

            /**
             * 컀밋해야 쿼리문이 μ‹€ν–‰λ˜λ©°,
             * ν•˜λ‚˜μ˜ νŠΈλžœμž­μ…˜μ΄ μ’…λ£Œλ˜λ©΄ λ°˜λ“œμ‹œ em(entity manager)λ₯Ό λ‹«μ•„μ•Ό ν•œλ‹€.
             */
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }

        emf.close();
    }
}