- Published on
π€Ώ μ¨ κΎΉ μ°Έκ³ λ₯λ€μ΄λΈ 3 : μ¨ κΎΉμ°Έκ³ λ₯λ€μ΄λΈ - JPA μμ¬νΈ
- Authors
- Name
- Woojin Son
μ¨ κΎΉμ°Έκ³ λ₯λ€μ΄λΈ - JPA μμ¬νΈ
Intro
π«§ βORMμ΄ μ΄λ κ²κΉμ§ μ€κΈ°κΉμ§, μΌλ§λ μ¨μ μ°ΈμμΌ νμκΉμ?"
λ€μ λμμμ΅λλ€. νλμ ν΄μκΈ°λ₯Ό μ’ κ°μ‘μ΅λλ€. κ°μΈμ μΌλ‘ λ€μ¬λ€λ ν 8μμ 보λμμ΄μ.
κ²½μ‘°μ¬λ μμκ³ , μ μ μ μ°¨λ €λ³΄λ μ΄λ―Έ 8μμ΄ μ¬λΌ μ Έ μμμμ£ .
JPA μ λν κΈμ νλ² μ°νκ² μ¨λ³Έ μ μ΄ μλ κ² κ°μ κΈμ μ¨λ³ΌκΉ ν©λλ€. JPA λ§μ΄λ€ μ°μμ£ .
μ²μ JPA λ₯Ό μΌλ μκΈ°κ° λ μ€λ¦ λλ€. μ μ μμ΄ λμ§ μμλ κΈ°μ΅μ΄ λ§μ΄ λ¨μμ. JDBC λ‘ DB 컀λ₯μ μ λ§λ€κ³ String Query λ₯Ό λ 리λ κ² νλΆ μμ μ κΈ°μ΅μ΄μλλ°...λ§μ κ·Έλ κ² μ€λ¬΄μμ μ 무λ₯Ό ν μΌμ μμμ΅λλ€.
μ€λ¬΄μμ 3λ μ°¨λ₯Ό μ§ννκ³ μλ μ΄ μκ°, JPA λ₯Ό μΌλ§λ μ μκ³ μ°κ³ μλ μ§ λ¬Έλ κΆκΈν΄μ‘μ΅λλ€. μ΄λ² ν¬μ€ν λ κ°λ₯νλ©΄ λκΉμ§ λ₯λ€μ΄λΈ ν΄ λ³΄κ² μ΅λλ€.
β μ»€νΌ νμ νλ©΄μ μ½μ΄μ£ΌμΈμ. μ΄λ²μλ λ₯λ€μ΄λΈ~! λ¬λ €λ³΄κ² μ΅λλ€.
JPA μκ°
Java Persistance Api λ μλ°μ§μμ λννλ Object Relational Mapping (ORM) μ λλ€. Java μ ν리μΌμ΄μ μμ λ°μ΄ν°μ μ§μ λ§λΏμμλ λΆλΆμ λ΄λΉνμ£ .
ORM μ΄λΌλ λ¨μ΄λ₯Ό νλ² λ©΄λ°ν λ³΄κ² μ΅λλ€. κ°μ²΄μ κ΄κ³μλ λ°μ΄ν°λ₯Ό λ§€ν μμΌμ£Όλ μν μ νλ κ² ORM μ΄μ£ . λ°μ΄ν°λ² μ΄μ€ λ΄ ν μ΄λΈμ λ°μ΄ν°λ₯Ό μ½μ΄μλ€λ©΄, μ€μ λ‘ μ¬μ©ν μ μλ κ°μ²΄λ‘ λ§€νν΄μ£Όλ μμ μ΄ νμν©λλ€. ORM λλΆμ μ°λ¦¬λ μ΄λ° μμ λ€μ μλμΌλ‘ νμ§ μμλ λ©λλ€.
ORM μ μ νμ§λ μ¬λ¬κ°μ§κ° μκ³ JPA λ κ·Έ μ€ νλμ λλ€. MyBatis λ₯Ό μΈ μλ μκ³ Kotlin λ² μ΄μ€μ κ°λ°μλΌλ©΄ Exposed λ₯Ό μ¬μ©ν μλ μμ£ . JPA λ μ€λ μκ° μ¬μ©λμ΄μ λ νΌλ°μ€κ° λ§μ ORM μ λλ€. μ΄μ§κ°ν΄μλ Spring μ ν리μΌμ΄μ μ κ°λ°ν λ μ€ν¨νμ§ μμ£ . λ€λ§, JPA κ·Έ μμ²΄κ° κ°μ§λ λ¨μ λ μλ€λ³΄λ μν©μ λ°λΌμ νλ¨ν΄μ μ¬μ©νμ μΌ ν©λλ€.
μ΄λ² ν¬μ€ν μμλ μ΄λ° κΈ°μ μ μΈ μ΄μΌκΈ°λ³΄λ€λ μμ¬μ λν μ΄μΌκΈ°λ₯Ό ν κΉ ν©λλ€. μ무리 μ΄λ² μ리μ¦μ λͺ©μ μ΄ λ₯λ€μ΄λΈλΌκ³ ν΄λ λ무 κΈ νλμμ λ΄μ©μ λ°©λνκ², κΉκ² λ€λ£¨λ©΄ νΌλ‘λκ° λμμ§λλΌκ΅¬μ.
JPA μμ¬ μ΄μΌκΈ°
1. JDBC μ μλ
νλΆμ λ μΉ μ ν리μΌμ΄μ κ°λ°μ Java λ₯Ό ν΅ν΄ λ°°μ λ³Έ μ¬λμ΄λΌλ©΄ μλ§ μλμ νλ‘μ°λ‘ λ°μ΄ν° μ κ·Όμ μ²λ¦¬νμ κ²μ λλ€.
Connection -> Statement -> ResultSet -> while(rs.next()) {...}
Connection conn = dataSource.getConnection();
PreparedStatement ps = conn.prepareStatement("SELECT * FROM MEMBER");
ResultSet rs = ps.executeQuery();
while (rs.next()) {
Member m = new Member();
m.setId(rs.getLong("id"));
m.setName(rs.getString("name"));
}
μ¬μ€ μ΄ νλ‘μΈμ€λ 2000λ λ μ΄λ°μ μλ° μ§μμ λ°μ΄ν° μ κ·Ό λ°©μμ μμ½ν κ²μ λλ€.
JSP μ Servlet, κ·Έλ¦¬κ³ HTML, CSS, JS λ‘ μΉ μ ν리μΌμ΄μ μμ μ λ€μλ μ μ΄ μμ΅λλ€. λΉμμ μμ μ΄ μ΄λ‘ μ λͺ©μ μ΄ μμλ€λ κ²μ κ°μνλ©΄, κ΅³μ΄ λ³΅μ‘ν Spring μ μ¬μ©νμ§ μμλ μ΄μ λ₯Ό μ΄ν΄ν μ μμμ£ . (νλΆμ κΈ°μ€μμ μΆ©λΆν 볡μ‘ν μ μλ€κ³ μκ°ν©λλ€. μ¬μ€ μ§κΈλ 볡μ‘ν΄μ...)
컀λ₯μ μ μ΄κ³ λ«λ κ², νΈλμμ μ μ²λ¦¬νλ κ², SQL μ μμ±νλ κ², κ·Έλ¦¬κ³ λ°μ΄ν°λ₯Ό λ§€ννλ κ² λͺ¨λ κ²λ€μ΄ μ²μμλ μλμΌλ‘ μ½λλ₯Ό μμ±νλ κ²μμ μμνμ΅λλ€.
μ΄ μ κ·Ό λ°©μμ λ¬Έμ κ° μλ€λ©΄ ν¬κ² μλμ κ°μ΅λλ€.
λ¨Όμ SQL μ μ§μ κ΄λ¦¬ν΄μΌ ν©λλ€. λΉμμ QueryDSL
κ°μ κ² μμ λ¦¬κ° μμ£ . μ€μ§ String μΌλ‘ κ΄λ¦¬ν΄μΌ ν©λλ€. κ·Έ λ§μ λ JDK 17 μ λ©ν°λΌμΈ String μ μΈ μ μμλ κ²λ μλκ²λλ€. λ¬Όλ‘ μ§κΈλ μ΄λ κ² κ°λ°νμλ λΆλ κ³μκ² μ§λ§, 2000λ
λ μ΄λ°μ΄λΌλ κ²μ κΈ°μ΅νμ
μΌ ν©λλ€. μ°λ¦¬κ° μ λ§ λ§μ΄ μ°κ³ μλ LTS μΈ JDK 8 μ΄ 2014λ
μ μΆμ λ λ²μ μ΄λΌλ κ²μ μμ΄μλ μλ©λλ€...
λ€μμΌλ‘ κ°μ²΄μ λ°μ΄ν°λ² μ΄μ€κ°μ λΆμΌμΉκ° μκΈΈ μ μμ΅λλ€. λ¬Όλ‘ μ΄κ±΄ μ§κΈλ λΉμ·νκ² μλκ° λΌκ³ μκ°ν μ μμ§λ§, κ°λ° κ³Όμ μμ ν μ΄λΈ λͺ μΈκ° λ³κ²½λλ κ²½μ° μλΉν λ§μ μ½λλ₯Ό μμ ν΄μΌ ν©λλ€. μ΅μν ORM μ μ°κ² λλ€λ©΄, ORM μ μμ μλ¬μ²λ¦¬λ₯Ό νκ±°λ μ»¬λΌ νλλ₯Ό 무μνκ±°λ λ± λμ²λ₯Ό ν μ μμ§λ§ νμ¬μ ꡬ쑰μμλ μ½μ§ μμ£ .
μ’ ν©μ μΌλ‘ λΉμ¦λμ€ λ‘μ§λ³΄λ€ SQL κ·Έ μ체μ κ΄λ¦¬ ν¬μΈνΈκ° λμ΄λλ λ¬Έμ κ° μκΉλλ€. SQL μ μμ±νλ κ² μμ²΄κ° λ¬Έμ λ μλκ² μ§λ§, μ μ μ½λλ₯Ό μμ±ν΄μΌ ν μκ°μ SQL μ μμ νλ κ²μ κ°λ° 곡μλ₯Ό μ‘μλ¨Ήλ μΌμ λλ€.
λ¬Όλ‘ λλ‘λ SQL λ‘ λμ°λκ² λμ μν©λ μκΈ°κΈ΄ ν©λλ€. ν΅κ³ μ²λ¦¬λ₯Ό ν λλ RDB μ λ°λΌ μ¬μ©ν μ μλ κΈ°λ₯λ€μ μ¨λ¨Ήλ κ² λμ μλ μμ£ .
μ§κΈ μ΄μΌκΈ°νλ λ΄μ©μ μ’ κ²°μ΄ λ€λ₯Έ λ΄μ©μ΄κΈ΄ ν©λλ€. SQL κ·Έ μμ²΄κ° κ°μ²΄λ‘ μμ±λ κ² μλμ΄μ λ°μ΄ν° νμ λ§ λ΄μλ String κ·Έ μ΄μ κ·Έ μ΄νλ μλ κ² νμ¬ μμ μμμ λ¬Έμ μ λλ€.
μμ μ¬νμ΄ μκΈ°λ , 볡μ‘νμ§λ§ νλ°©μΌλ‘ λ¬Έμ λ₯Ό ν΄κ²°ν μ μλ 쿼리λ₯Ό μ°λ μ°λ¦¬κ° μμ νκ³ κ΄λ¦¬νλ SQL μ΄ String λ³μ νλμ μ λΆ μ§±λ°νμλ€κ³ μκ°ν΄λ³΄λ©΄ μ΄ν΄κ° μ’ λ μ¬μΈ κ² κ°μ΅λλ€. 쑰건μ λ°λΌ WHERE λ¬Έμ λ£μλ€ λΉΌκ³ μΆμλ° μ΄ μν©μμ μ΄λ»κ² νλ©΄ μ’μκΉμ...?
μ΄μ―€ λλ©΄ λκ΅°κ°λ μ΄λ° μκ°μ ν μλ μμ κ² κ°μ΅λλ€.
μλ κ± μ΄κ±° λΉλκ°μκ±Έλ‘ ν΄κ²° λͺ»νλ?
SQL κ΄λ¦¬μ κ°μ²΄λ₯Ό νμ©ν΄λ³΄μ! λΌλ μκ°μ λκ΅°κ° νκΈ° μμνκ³ , 2001λ κ²½ κ·Έ μμ΄λμ΄λ₯Ό μ€ν ν νλ‘μ νΈκ° λ±μ₯νμ΅λλ€.
2. Hibernate μ λ±μ₯ (2001 ~)
Hibernate λ μ°λ¦¬κ° μ΄λ―Έ μ μκ³ μλ ORM μ λλ€. κ·Έ μ μλ μλκ° μμλ κ²μ μλλ°, λ°λ‘ EJB μ Entity Bean μ λλ€. νμ§λ§ EJB μ Entity Bean μ 볡μ‘ν XML μ€μ κ³Ό Vendor μ’ μμ±μ΄ μμμ΅λλ€. (EJB κ·Έ μ체μ λ¬Έμ μΌ κ² κ°μ΅λλ€.)
Hibernate λ μ΅λν λ¨μνκ² Annotation λ² μ΄μ€λ‘ μ΅μ μ μ§μ ν μ μκ³ , μ ν리μΌμ΄μ μμμμ νΈλμμ μ 컨νΈλ‘€ ν μ μλ€λ μ°¨λ³μ μ κ°μ‘μ΅λλ€. λν 1μ°¨, 2μ°¨ μΊμ κΈ°λ₯κ³Ό κ°μ μ¬ν κΈ°λ₯μ μ 곡νμ£ .
κ°μ₯ κ²°μ μ μΌλ‘ DB μ€μ¬μ΄ μλ μ ν리μΌμ΄μ μ κ°μ²΄ μ€μ¬μ μ€κ³ μ² νμ κ°μ‘μ΅λλ€. μ ν리μΌμ΄μ μμμμκΉμ§ DBμ μμ‘΄μ±μ κ°μ Έκ°μ§ μμΌλ €κ³ λ Έλ ₯νλ€λ μλ―Έμ£ .
μ΄μ μλ DB μ€ν€λ§ κ·Έ μμ²΄κ° μ ν리μΌμ΄μ
μ μ€κ³λ₯Ό μ§λ°°νλ κ²μ΄ μΌλ°μ μΈ μν©μ΄μμ΅λλ€. Hibernate λ ν
μ΄λΈμ΄ μλ κ°μ²΄ λͺ¨λΈ (entity) λ₯Ό μ°μ νμ£ . κ°μ²΄κ°μ μ°κ΄κ΄κ³κ° κ³§ λ°μ΄ν°μ κ΄κ³κ° λ μ μλλ‘ μ€κ³λμμ΅λλ€. Member.team
, Order.items
μ κ°μ μ°κ΄κ΄κ³λ±μ΄ κ·Έ μμμ
λλ€.
λν JDBC λ§ μΈ λμλ λ€λ₯΄κ², κ°μ²΄μ μν λ³ν κ·Έ μ체λ₯Ό μΆμ νλ κΈ°λ₯μ΄ μ‘΄μ¬νμ΅λλ€. JDBC λ μ§μ UPDATE Query λ₯Ό λ λ €μ€μΌ νμ£ . Hibernate μμλ κ·Έλ΄ νμκ° μμ΅λλ€.
member.setName("DevCow");
tx.commit(); // UPDATE μλ μ€ν (Dirty Checking)
κ°λ°μλ λλΆμ λ°μ΄ν° μ‘°μμ΄ μλλΌ κ°μ²΄μ μν μ μ΄ (state transition) μ λ€λ£¨κ² λμμ£ .
λν κ°μ²΄κ°μ μ°κ΄κ΄κ³ κ·Έ μμ²΄κ° λ°μ΄ν°μ κ΄κ³λ‘ μΈν΄ λ°μ΄ν° ν (Row) λ¨μκ° μλ κ°μ²΄ κ·Έ μ체λ₯Ό μ€μ¬μΌλ‘ μ½λλ₯Ό μμ±ν μ μκ² λμμ΅λλ€.
member.getTeam().getName(); // Lazy LoadingμΌλ‘ μλ μ‘°ν
JDBC μμΌλ©΄ Join Query λ₯Ό μμ±ν΄μ λ λ €μΌ ν©λλ€. κ·Έλ κ² μ‘°ν λ Row λ€μ λ λ€μ κ°κ³΅ν΄μΌ νμ£ . μ΄λ° κΈ°λ₯ λλΆμ DB ν μ΄λΈμ΄ μλ κ°μ²΄κ°μ λ€νΈμν¬κ° μ¬κ³ μ λ¨μκ° λ μ μμ΅λλ€.
Hibernate λ ν¬κ² λ€ κ°μ§ ν΅μ¬ κΈ°λ₯μ κ°μ§κ³ μμ΅λλ€.
- Lazy Loading : νμν μμ μλ§ λ‘λ©
- Dirty Checking : λ³κ²½ μλ κ°μ§
- Session Cache : λμΌ νΈλμμ λ΄ λμΌ κ°μ²΄ 보μ₯
- HQL : SQLμ μΆμνν κ°μ²΄μ§ν₯ 쿼리
3. JPA μ νμ (2006)
Hibernateμ μ±κ³΅μ λμ¬κ²¨λ³Έ **Java Community Process (JCP)**λ κ° λ²€λμ ORM κΈ°μ μ ν΅ν©ν΄ νμ€μ λ§λ€κΈ°λ‘ κ²°μ ν©λλ€.
λΉμμ Hibernate μΈμλ λ€λ₯Έ ORM λ€μ΄ λ§μ΄ μλλλ μκΈ°μμ΅λλ€.
2006λ , EJB 3.0κ³Ό ν¨κ» **JPA 1.0 (Java Persistence API)**μ΄ λ°νλ©λλ€. Hibernate μ Toplink, Kodo μ νμ체μμ λ°νλμμ£ .
@Entity
class Member {
@Id @GeneratedValue
Long id;
String name;
}
μ΄ μ½λ λͺμ€λ‘ κ°μ²΄κ° μμμ± (persistence) λ₯Ό κ°μ§κ² λμμ£ . κ·Έλμμ μλ λ§€νμ΄ μ΄λ κ² μ¬νν΄μ‘μ΅λλ€.
4. JPA 2.x - ORMμ μ μ κΈ°
κ·Έ μ΄νλ‘ JPA λ κ³μν΄μ λ²μ μ μ¬λ¦¬λ©° νμ€μ μ‘μ κ°μ΅λλ€. κ°λ΅ν ν¨μΉλ ΈνΈλ μλμ κ°μ΅λλ€.
Jpa 2.0 (2009)
- Criteria APIλ‘ νμ μΈμ΄νν 쿼리 μ 곡
- ElementCollection, MapKey λ± μ»¬λ μ λ§€ν κ°ν
- 1μ°¨ μΊμ, Flush λͺ¨λ νμ€ν
JPA 2.1 (2013)
- EntityGraph: Fetch μ λ΅ λμ μ μ΄
- AttributeConverter: VO β μ»¬λΌ λ³ν
- Stored Procedure νΈμΆ μ§μ
μ΄ μκΈ° λΆν°λ Spring Data JPA κ° λ±μ₯νκΈ° μμνμ΅λλ€. μ°λ¦¬κ° μ΅μ ν Repository μΈν°νμ΄μ€, CRUD μλμμ±μ μλκ° μ΄λ¦°κ±°μ£ .
Hibernate λ μ¬μ ν JPA μ ꡬνμ²΄λ‘ μ§ννμ΅λλ€. μ²μλΆν° JPA μ ꡬν체λ μλμκ² μ§λ§, νμ€μ μ‘μκ°λ©° μ¬μ€μ JPAλΌλ νμ€μ ꡬνμ²΄κ° Hibernate κ° λλ κ΅¬μ‘°κ° κ΅³μ΄μ§κ² λμ£ .
5. Jakarta Persistence - νμ€μ κ³μΉ (2019 ~ )
2019λ μ ν μ¬κ±΄μ΄ ν°μ§λλ€. Oracle μ΄ Java EE λ₯Ό Eclipse μ¬λ¨μ μ΄κ΄νκ² λμμ£ . κ·Έ κ²°κ³Ό λͺ¨λ ν¨ν€μ§λ€μ΄ javax μμ jakarta λ‘ λ³κ²½λμμ΅λλ€. λμ΄μ Java EE κ° μλλΌ Jakarta EE λ₯Ό λ°λ₯΄κ² λμκ΅ JPA 3.0 μ μλκ° μ€κ² λμμ£ .
JPA μΈμ ORM?
JPA κ° μΈμμ λμ¨ μ§ μκ°μ΄ κ½€ μ€λ μ§λ¬μ£ . νμ¬λ μ λ§ λ€μν μ νμ§λ€μ΄ μ‘΄μ¬ν©λλ€. Spring Data JPA μ QueryDSL μ μ‘°ν©μ κ΅λ£° μ‘°ν©μΌλ‘ μ λͺ νμ£ . νμ§λ§ κ·Έ μΈμλ jOOQ, Exposed (Kotlin) κ³Ό κ°μ μ νμ§λ μ‘΄μ¬ν©λλ€. λ ΌλΈλ‘νΉ DB μ κ·Όμ΄ νμν κ²½μ°μ R2DBC κ° μꡬλκΈ°λ νμ£ .
κ°μΈμ μΌλ‘λ JPA + QueryDSL μ μ‘°ν©μ κ°μ₯ μ€λ μ¬μ©νμ§λ§, μ΅κ·Όμλ Exposed λ₯Ό μ¬μ©ν΄λ³΄λ €κ³ λ Έλ ₯μ€μ λλ€. Java κ·Έ μ체μ λ¨μ μ Kotlin μ΄ λ§μ΄ 보μν΄μ£Όλ λ§νΌ Java μ λ§κ² μ΅μ ν λ Spring Data JPA μμ λ²μ΄λλ³΄λ €κ³ μ‘°κΈμ© λ Έλ ₯ ν΄ λ³΄κ³ μμ΅λλ€.
Outro
JPA μ μμ¬λ ORM μ΄λΌλ κΈ°μ μ΄ λ°μ ν΄ λκ°κ³ νμ€νκ° μ΄λ€μ§λ κ³Όμ κ·Έ μ체λΌκ³ λ λ³Ό μ μμ΅λλ€. λ§μ κ°λ°μλ€μκ² κ°μ²΄μ§ν₯
κ·Έ μ체μ μ€μμ±μ μ§μ€ν μ μλλ‘ μ 립 ν΄ κ°λ κ³Όμ μ μ λμ보면μ, μ€μ λ‘ κ°λ°μλ€μ μ½λ μμ± ν¨λ¬λ€μμ μλΉν λ§μ΄ λ°κΏ¨λ€λ κ²μ 체κ°νμ΅λλ€.
λ€μ νΈμμλ JPA μ λ΄λΆλ‘ κΉκ² νκ³ λ€μ΄κ°λ μλμ리
νΈμ
λλ€. κΈ°λν΄μ£ΌμΈμ~πββοΈ