[Spring / JPA] JPA ๊ฐœ๋…

DevelopHeoยท2025๋…„ 1์›” 10์ผ
post-thumbnail

๐Ÿ“™ 1. JPA๋ž€?

JPA(Java Persistence API)๋Š” ์ž๋ฐ” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•œ ORM(Object-Relational Mapping) ๊ธฐ์ˆ ์ž…๋‹ˆ๋‹ค. JPA๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด SQL์„ ์ง์ ‘ ์ž‘์„ฑํ•˜์ง€ ์•Š๊ณ ๋„ ์ž๋ฐ” ๊ฐ์ฒด์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ” ๊ฐ„์˜ ๋งคํ•‘์„ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์‰ฝ๊ฒŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • JPA๋Š” ์ธํ„ฐํŽ˜์ด์Šค์ด๋‹ค. ๋”ฐ๋ผ์„œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ์‹ค์ œ ํด๋ž˜์Šค๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

โœ๏ธ ์ฃผ์š” ํŠน์ง•

  1. ORM ์ง€์›: JPA๋Š” ์ž๋ฐ” ๊ฐ์ฒด์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”์„ ๋งคํ•‘ํ•˜์—ฌ ๊ฐ์ฒด ์ง€ํ–ฅ์ ์ธ ๋ฐฉ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
  2. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋…๋ฆฝ์„ฑ: JPA๋Š” ํŠน์ • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ข…์†๋˜์ง€ ์•Š์œผ๋ฉฐ, ์—ฌ๋Ÿฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์ž‘๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  3. ์ž๋™ SQL ์ƒ์„ฑ: JPA๋Š” ํ•„์š”ํ•œ SQL ์ฟผ๋ฆฌ๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜์—ฌ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ SQL์„ ์ž‘์„ฑํ•  ํ•„์š”๋ฅผ ์ค„์ž…๋‹ˆ๋‹ค.
  4. ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ: JPA๋Š” ํŠธ๋žœ์žญ์…˜์„ ๊ด€๋ฆฌํ•˜์—ฌ ๋ฐ์ดํ„ฐ์˜ ์ผ๊ด€์„ฑ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.
  5. ์บ์‹ฑ: JPA๋Š” 1์ฐจ ์บ์‹œ์™€ 2์ฐจ ์บ์‹œ๋ฅผ ์ง€์›ํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์•ก์„ธ์Šค๋ฅผ ์ตœ์ ํ™”ํ•ฉ๋‹ˆ๋‹ค.

โœ๏ธ ์ฃผ์š” ๊ตฌ์„ฑ ์š”์†Œ

  1. Entity : ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”๊ณผ ๋งคํ•‘๋˜๋Š” ์ž๋ฐ” ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค. ๊ฐ ์—”ํ‹ฐํ‹ฐ๋Š” @Entity ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ์ •์˜๋ฉ๋‹ˆ๋‹ค.
  2. EntityManager: ์—”ํ‹ฐํ‹ฐ์˜ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋กœ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  3. EntityManagerFactory: EntityManager๋ฅผ ์ƒ์„ฑํ•˜๋Š” ํŒฉํ† ๋ฆฌ ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค.
  4. Persistence Unit: JPA ์„ค์ •์„ ํฌํ•จํ•˜๋Š” ๋‹จ์œ„๋กœ, persistence.xml ํŒŒ์ผ์— ์ •์˜๋ฉ๋‹ˆ๋‹ค.

๐Ÿ“™ 2. JPA ๊ฐ„๋‹จ ์˜ˆ์ œ ์ฝ”๋“œ

1. ์—”ํ‹ฐํ‹ฐ ํด๋ž˜์Šค ์ •์˜

import jakarta.persistence.Entity;
import jakarta.persistence.Id;

@Entity
public class User {
    @Id
    private Long id;
    private String name;
    private String email;

    // Getters and setters
}

2. persistence.xml ์„ค์ •

<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.1">
    <persistence-unit name="examplePU">
        <class>com.example.User</class>
        <properties>
            <property name="jakarta.persistence.jdbc.url" value="jdbc:h2:mem:test"/>
            <property name="jakarta.persistence.jdbc.user" value="sa"/>
            <property name="jakarta.persistence.jdbc.password" value=""/>
            <property name="jakarta.persistence.jdbc.driver" value="org.h2.Driver"/>
        </properties>
    </persistence-unit>
</persistence>

3. ์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ € ์‚ฌ์šฉ

import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;

public class Main {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("examplePU");
        EntityManager em = emf.createEntityManager();

        em.getTransaction().begin();
        User user = new User();
        user.setId(1L);
        user.setName("John Doe");
        user.setEmail("john.doe@example.com");
        em.persist(user);
        em.getTransaction().commit();

        em.close();
        emf.close();
    }
}
  • JPA๋Š” ์ด๋Ÿฌํ•œ ๋ฐฉ์‹์œผ๋กœ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋” ์‰ฝ๊ฒŒ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์ƒํ˜ธ ์ž‘์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค๋‹ˆ๋‹ค.

๐Ÿ“™ 3. ORM์ด๋ž€?

ORM : Object-Relational Mapping(๊ฐ์ฒด ๊ด€๊ณ„ ๋งคํ•‘)

  • ๊ฐ์ฒด์™€ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋งคํ•‘ํ•˜๋Š” ๊ธฐ์ˆ 
  • ORM ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ๊ฐ์ฒด์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ค‘๊ฐ„์—์„œ ๋งคํ•‘
  • ๊ฐ์ฒด์™€ ํ…Œ์ด๋ธ”์„ ๋งคํ•‘ํ•˜์—ฌ ํŒจ๋Ÿฌ๋‹ค์ž„ ๋ถˆ์ผ์น˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐ
  • ORM์„ ์ด์šฉํ•˜๋ฉด ๊ฐœ๋ฐœ์ž๊ฐ€ ์ฟผ๋ฆฌ๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•˜์ง€ ์•Š์•„๋„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ Class์™€ RDB(Relational DataBase)์˜ ํ…Œ์ด๋ธ”์„ ๋งคํ•‘(์—ฐ๊ฒฐ)ํ•œ๋‹ค๋Š” ๋œป

โœ๏ธ ORM ์žฅ์ 

  • SQL ๋Œ€์‹  ๋ฉ”์„œ๋“œ๋กœ DB ์กฐ์ž‘: ๊ฐœ๋ฐœ์ž๋Š” ๊ฐ์ฒด ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์—๋งŒ ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ฝ”๋“œ ๊ฐ„์†Œํ™”: ๋ถ€์ˆ˜์ ์ธ ์ฝ”๋“œ๋ฅผ ์ค„์—ฌ ๊ฐ€๋…์„ฑ์„ ๋†’์ž…๋‹ˆ๋‹ค.
  • ๊ฐ์ฒด์ง€ํ–ฅ์  ์ฝ”๋“œ ์ž‘์„ฑ: ๊ฐ์ฒด์ง€ํ–ฅ ์ ‘๊ทผ์„ ํ†ตํ•ด ์ƒ์‚ฐ์„ฑ์ด ์ฆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
  • ์œ ์ง€๋ณด์ˆ˜ ์šฉ์ด: ๋งคํ•‘ ์ •๋ณด๊ฐ€ ํด๋ž˜์Šค์— ๋ช…์‹œ๋˜์–ด ์žˆ์–ด ERD ์˜์กด๋„๋ฅผ ๋‚ฎ์ถ”๊ณ , ์œ ์ง€๋ณด์ˆ˜ ๋ฐ ๋ฆฌํŒฉํ† ๋ง์— ์œ ๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ณ€๊ฒฝ์— ์œ ์—ฐ: ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๋ณ€๊ฒฝํ•ด๋„ ์ฟผ๋ฆฌ ์ˆ˜์ •์ด ํ•„์š” ์—†์Šต๋‹ˆ๋‹ค.

โœ๏ธ ORM ๋‹จ์ 

  • ์„ค๊ณ„์˜ ์ค‘์š”์„ฑ: ์„ค๊ณ„๊ฐ€ ์ž˜๋ชป๋˜๋ฉด ์†๋„ ์ €ํ•˜ ๋ฐ ์ผ๊ด€์„ฑ ๋ฌธ์ œ๋ฅผ ์ดˆ๋ž˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค
  • ๋ณต์žกํ•œ ์ฟผ๋ฆฌ: ์„ฑ๋Šฅ์„ ์œ„ํ•ด ๋ณต์žกํ•œ ์ฟผ๋ฆฌ๋Š” ํŠœ๋‹์ด ํ•„์š”ํ•˜๋ฉฐ, ๊ฒฐ๊ตญ SQL์„ ์จ์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํ•™์Šต ๋น„์šฉ: ํ•™์Šต ๊ณก์„ ์ด ๋†’์•„ ์ดˆ๊ธฐ ๋„์ž… ๋น„์šฉ์ด ํด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“™ 4. JPA์˜ ๋™์ž‘

โœ๏ธ JPA์˜ ๋™์ž‘

JPA๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ JDBC ์‚ฌ์ด์—์„œ ๋™์ž‘ํ•œ๋‹ค.

  • JPA๋Š” JDBC API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›๊ฒŒ ๋œ๋‹ค.

์ €์žฅ

  • MemberDAO ํด๋ž˜์Šค๋ฅผ ํ†ตํ•ด persist()๋ฅผ ์‹คํ–‰ํ•˜๋ฉด, JPA๊ฐ€ Entity ๊ฐ์ฒด๋ฅผ ๋ถ„์„ํ•˜์—ฌ SQL๋ฌธ์„ ์ƒ์„ฑํ•œ๋‹ค.
  • JDBC API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ DB์— ์ƒ์„ฑ๋œ INSERT SQL์„ ๋ณด๋‚ด๊ฒŒ ๋œ๋‹ค.
  • ์ด ๊ณผ์ •์—์„œ JPA๋Š” ๊ฐ์ฒด์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”์˜ ํŒจ๋Ÿฌ๋‹ค์ž„ ๋ถˆ์ผ์น˜๋ฅผ ํ•ด๊ฒฐํ•œ๋‹ค.

์กฐํšŒ

  • MemberDAO ํด๋ž˜์Šค๋ฅผ ํ†ตํ•ด find(id)๋ฅผ ์‹คํ–‰ํ•˜๋ฉด, JPA๋Š” SELECT SQL์„ ์ƒ์„ฑํ•œ๋‹ค.
  • JDBC API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒ์„ฑ๋œ SELECT SQL์„ ๋ณด๋‚ธ๋‹ค.
  • DB์—์„œ ๋ฐ˜ํ™˜๋œ ์ •๋ณด๋ฅผ ResultSet ๋งคํ•‘์„ ํ†ตํ•ด ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•ด ์ค€๋‹ค.
  • ์ด ๊ณผ์ •์—์„œ๋„ ํŒจ๋Ÿฌ๋‹ค์ž„ ๋ถˆ์ผ์น˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด ์ค€๋‹ค.

โœ๏ธ JPA์˜ ์ƒ์‚ฐ์„ฑ(CRUD)

  • JPA๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ธฐ๋ณธ์ ์œผ๋กœ ์ƒ์‚ฐ์„ฑ์ด ๋†’์•„์ง„๋‹ค. JDBC ๋ฐฉ์‹์˜ ๊ฒฝ์šฐ SQL ์ฟผ๋ฆฌ๋ฌธ์„ ์ง์ ‘ ์ž‘์„ฑํ•ด์•ผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ํ•˜์ง€๋งŒ JPA๋Š” ์ฟผ๋ฆฌ๋ฌธ์„ ๋ณ„๋„๋กœ ์ž‘์„ฑํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค. ๋Œ€์‹  ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฐ„๋‹จํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด CRUD๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.
  • ์ €์žฅ : jpa.persist(member)
  • ์กฐํšŒ : Member member = jpa.find(memberId)
  • ์ˆ˜์ • : member.setName(โ€๋ณ€๊ฒฝํ•  ์ด๋ฆ„โ€)
  • ์‚ญ์ œ : jpa.remove(member)

โœ๏ธ JPA ์œ ์ง€๋ณด์ˆ˜

๊ธฐ์กด์—๋Š” ์—”ํ‹ฐํ‹ฐ ํด๋ž˜์Šค์˜ ํ•„๋“œ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ๋ชจ๋“  SQL์„ ์ˆ˜์ •ํ•ด์•ผ ํ–ˆ๋‹ค.
JPA์—์„œ๋Š” ์ฟผ๋ฆฌ๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ํ•„๋“œ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋”๋ผ๋„ ๋งคํ•‘ ์ •๋ณด๋งŒ ์ž˜ ์—ฐ๊ฒฐํ•˜๋ฉด SQL๋ฌธ์€ ์ž๋™์œผ๋กœ ์ž‘์„ฑ๋œ๋‹ค.

  • ์ด์™€ ๊ฐ™์ด ๊ฐ์ฒด์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋Š” ์„œ๋กœ ๋‹ค๋ฅธ ๋ชฉ์ ์„ ๊ฐ€์ง€๊ณ  ์„ค๊ณ„๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋งคํ•‘ํ•˜๋Š”๋ฐ ์žˆ์–ด ์—ฌ๋Ÿฌ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ํ•˜์ง€๋งŒ JPA๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ๋ชจ๋‘ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ“™ 5. JPA์˜ ๋™์ž‘ ์˜ˆ์‹œ ์ฝ”๋“œ

ํ…Œ์ด๋ธ” ๊ตฌ์„ฑ ์˜ˆ์‹œ

idsubjectcontent
1์ถœ์„1์ผ์ฐจ1์ผ์งธ ์ž…๋‹ˆ๋‹ค
2์ถœ์„2์ผ์ฐจ2์ผ์งธ ์ž…๋‹ˆ๋‹ค

sql ์ฟผ๋ฆฌ๋กœ ์ž‘์„ฑํ•œ๋‹ค๋ฉด?

creat table board(
	id int primary key,
    subject varchar(100) not null,
    content varchar(1000) not null
);

insert into question (subject, content) 
values ('์ถœ์„1์ผ์ฐจ', '1์ผ์งธ ์ž…๋‹ˆ๋‹ค'), ('์ถœ์„2์ผ์ฐจ', '2์ผ์งธ ์ž…๋‹ˆ๋‹ค');

ORM์„ ์ด์šฉํ•˜์—ฌ ์ž‘์„ฑํ•œ๋‹ค๋ฉด!

board q1 = new board();
q1.setSubject("์ถœ์„1์ผ์ฐจ");
q1.setContent("1์ผ์งธ ์ž…๋‹ˆ๋‹ค");
this.boardRepository.save(q1);

board q2 = new board();
q2.setSubject("์ถœ์„2์ผ์ฐจ");
q2.setContent("2์ผ์งธ ์ž…๋‹ˆ๋‹ค");
this.boardRepository.save(q2);
  • ์ฝ”๋“œ์—์„œ board์€ ์ž๋ฐ” ํด๋ž˜์Šค์ด๋ฉฐ, ์ด์ฒ˜๋Ÿผ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•˜๋Š” ORM ํด๋ž˜์Šค๋ฅผ ์—”ํ‹ฐํ‹ฐ(Entity)๋ผ๊ณ  ํ•œ๋‹ค.
  • ORM์„ ์ด์šฉํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ข…๋ฅ˜์— ์ƒ๊ด€ ์—†์ด ์ผ๊ด€๋œ ์ฝ”๋“œ๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์–ด์„œ ํ”„๋กœ๊ทธ๋žจ์„ ์œ ์ง€ยท๋ณด์ˆ˜ํ•˜๊ธฐ๊ฐ€ ํŽธ๋ฆฌํ•˜๋‹ค.
  • ๋˜ํ•œ ๋‚ด๋ถ€์—์„œ ์•ˆ์ „ํ•œ SQL ์ฟผ๋ฆฌ๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•ด ์ฃผ๋ฏ€๋กœ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋‹ฌ๋ผ๋„ ํ†ต์ผ๋œ ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ณ  ์˜ค๋ฅ˜ ๋ฐœ์ƒ๋ฅ ๋„ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

์ถœ์ฒ˜ :

0๊ฐœ์˜ ๋Œ“๊ธ€