spring

JPA๊ธฐ์ดˆ @Entity & @Id & @GeneratedValue & ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ

devJK93 2024. 11. 23.

๐Ÿ”ฅ JPA๋ž€ ๋ฌด์—‡์ธ๊ฐ€? ๊ทธ๋ฆฌ๊ณ  @Entity, @Id, @GeneratedValue์˜ ์—ญํ• 

JPA๋ž€?

  • JPA(Java Persistence API)๋Š” ์ž๋ฐ” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๊ฐ์ฒด(ํด๋ž˜์Šค)์™€ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ฐ„์˜ ๋งคํ•‘์„ ์ •์˜ํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ํ‘œ์ค€ ์ธํ„ฐํŽ˜์ด์Šค์ž…๋‹ˆ๋‹ค.
  • ์—ญํ• :
    • ๊ฐ์ฒด์™€ ํ…Œ์ด๋ธ” ๊ฐ„์˜ ๋งคํ•‘์„ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌ (ORM: Object-Relational Mapping).
    • SQL ์—†์ด๋„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์ƒํ˜ธ์ž‘์šฉ ๊ฐ€๋Šฅ.
    • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋…๋ฆฝ์ ์ธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ ์ง€์›.
  • ๊ตฌํ˜„์ฒด: Hibernate, EclipseLink, OpenJPA ๋“ฑ์ด ์žˆ์œผ๋ฉฐ, JPA๋Š” ์ด ๊ตฌํ˜„์ฒด๋“ค์„ ์œ„ํ•œ ํ‘œ์ค€์ž…๋‹ˆ๋‹ค.

@Entity

์—ญํ• : ํด๋ž˜์Šค๊ฐ€ JPA ์—”ํ„ฐํ‹ฐ์ž„์„ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”๊ณผ ๋งคํ•‘๋ฉ๋‹ˆ๋‹ค.


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

์œ„ ์ฝ”๋“œ์—์„œ User ํด๋ž˜์Šค๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ user ํ…Œ์ด๋ธ”๊ณผ ๋งคํ•‘๋ฉ๋‹ˆ๋‹ค.

@Id

์—ญํ• : Primary Key๋กœ ์‚ฌ์šฉํ•  ํ•„๋“œ๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ์—”ํ„ฐํ‹ฐ์˜ ๊ฐ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ณ ์œ ํ•˜๊ฒŒ ์‹๋ณ„ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.


@Entity
public class User {
    @Id
    private Long id;  // Primary Key
}
    

id ํ•„๋“œ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ Primary Key๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

@GeneratedValue

์—ญํ• : Primary Key์˜ ๊ฐ’์„ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์–‘ํ•œ ์ƒ์„ฑ ์ „๋žต์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

์ƒ์„ฑ ์ „๋žต:

  • GenerationType.AUTO: JPA ๊ตฌํ˜„์ฒด๊ฐ€ ์ ์ ˆํ•œ ์ „๋žต์„ ์„ ํƒ.
  • GenerationType.IDENTITY: ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ AUTO_INCREMENT ๊ธฐ๋Šฅ ์‚ฌ์šฉ.
  • GenerationType.SEQUENCE: ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ Sequence ๊ฐ์ฒด ์‚ฌ์šฉ.
  • GenerationType.TABLE: ํ‚ค ๊ฐ’์„ ์ €์žฅํ•˜๋Š” ๋ณ„๋„์˜ ํ…Œ์ด๋ธ” ์‚ฌ์šฉ.

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
}
    

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ id๋Š” ์ž๋™์œผ๋กœ ์ฆ๊ฐ€ํ•˜๋Š” ๊ฐ’์œผ๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค.

์˜ˆ์ œ ์ฝ”๋“œ ์ „์ฒด


import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;

@Entity
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    // Getters and setters
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
    

JPA๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์ฃผ์š” ์žฅ์ 

  • ์ƒ์‚ฐ์„ฑ ํ–ฅ์ƒ: ๋ฐ˜๋ณต์ ์ธ SQL ์ž‘์„ฑ ์—†์ด CRUD ์ž‘์—… ๊ฐ€๋Šฅ.
  • ์œ ์ง€๋ณด์ˆ˜ ์šฉ์ด์„ฑ: ๊ฐ์ฒด ์ค‘์‹ฌ์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฏ€๋กœ ๊ฐ€๋…์„ฑ์ด ์ข‹์Œ.
  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋…๋ฆฝ์„ฑ: ํŠน์ • DBMS์— ์ข…์†๋˜์ง€ ์•Š๊ณ , ๋‹ค์–‘ํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๋™์ผํ•œ ์ฝ”๋“œ๋กœ ๋™์ž‘.

๋™์ž‘ ์›๋ฆฌ ์š”์•ฝ

  1. JPA๊ฐ€ User ์—”ํ„ฐํ‹ฐ๋ฅผ user ํ…Œ์ด๋ธ”์— ๋งคํ•‘ํ•ฉ๋‹ˆ๋‹ค.
  2. id๋Š” Primary Key๋กœ ์„ค์ •๋˜๋ฉฐ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์ž๋™ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.
  3. SQL ์ž‘์„ฑ ์—†์ด๋„ ๋ฐ์ดํ„ฐ ์ €์žฅ, ์กฐํšŒ, ์‚ญ์ œ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

 

 

๐Ÿ”ฅ @Id์™€ @GeneratedValue๊ฐ€ ์—†์—ˆ์„ ๋•Œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ๋งคํ•‘

1. @Id๊ฐ€ ์—†์—ˆ์„ ๋•Œ

JPA์—์„œ @Id๋Š” Primary Key๋ฅผ ์ง€์ •ํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜์ž…๋‹ˆ๋‹ค. ๋งŒ์•ฝ @Id๊ฐ€ ์—†์—ˆ๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค:

  • Primary Key ๋ฏธ์ง€์ •์œผ๋กœ ์ธํ•ด JPA๊ฐ€ ๋งคํ•‘ ๋ถˆ๊ฐ€๋Šฅ: JPA๋Š” ์—”ํ„ฐํ‹ฐ๋ฅผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”์˜ ์–ด๋–ค ๋ ˆ์ฝ”๋“œ์™€ ๋งคํ•‘ํ• ์ง€ Primary Key๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํŒ๋‹จํ•ฉ๋‹ˆ๋‹ค. @Id๊ฐ€ ์—†์œผ๋ฉด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
  • ์—๋Ÿฌ ๋ฉ”์‹œ์ง€:
    
    javax.persistence.PersistenceException: No identifier specified for entity: com.example.User
                
  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”์— ์ด๋ฏธ Primary Key๊ฐ€ ์„ค์ •๋˜์–ด ์žˆ์–ด๋„, JPA๋Š” ์ด๋ฅผ ์ธ์‹ํ•˜์ง€ ๋ชปํ•˜๊ณ  ๋ช…์‹œ์ ์œผ๋กœ @Id๋ฅผ ์š”๊ตฌํ•ฉ๋‹ˆ๋‹ค.

2. @GeneratedValue๊ฐ€ ์—†์—ˆ์„ ๋•Œ

Primary Key์˜ ์ž๋™ ์ƒ์„ฑ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. Primary Key ๊ฐ’์„ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ๊ด€๋ฆฌํ•ด์•ผ ํ•˜๋ฉฐ, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

  • ์ž๋™ ์ฆ๊ฐ€ ๊ธฐ๋Šฅ ์ƒ์‹ค: ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ Primary Key๋ฅผ ์ž๋™์œผ๋กœ ์ฆ๊ฐ€์‹œํ‚ค์ง€ ๋ชปํ•˜๋ฏ€๋กœ, ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ €์žฅํ•˜๊ธฐ ์ „์— Primary Key ๊ฐ’์„ ์ˆ˜๋™์œผ๋กœ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • Primary Key ๋ˆ„๋ฝ ์‹œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—๋Ÿฌ: Primary Key ๊ฐ’์ด ์—†์œผ๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์ œ์•ฝ ์กฐ๊ฑด ์œ„๋ฐ˜ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
  • ์˜ˆ์‹œ ์ฝ”๋“œ (Primary Key ๊ฐ’ ์ˆ˜๋™ ์„ค์ •):
    
    @Entity
    public class User {
        @Id
        private Long id;  // Primary Key๋ฅผ ์ง์ ‘ ์„ค์ •ํ•ด์•ผ ํ•จ
    
        private String name;
    }
    
    // ๋ฐ์ดํ„ฐ ์ €์žฅ ์‹œ
    User user = new User();
    user.setName("Alice");
    user.setId(1L);  // Primary Key๋ฅผ ์ˆ˜๋™์œผ๋กœ ์„ค์ •
    entityManager.persist(user);  // ์ •์ƒ ๋™์ž‘
                
  • Primary Key๋ฅผ ์ˆ˜๋™์œผ๋กœ ์„ค์ •ํ•˜์ง€ ์•Š์œผ๋ฉด ์—๋Ÿฌ ๋ฐœ์ƒ:
    
    org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save()
                

3. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๋งคํ•‘๋œ ๊ฒฐ๊ณผ

Primary Key๊ฐ€ ์—†๊ฑฐ๋‚˜ ์ž๋™ ์ƒ์„ฑ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

    • ์ค‘๋ณต๋œ ๋ ˆ์ฝ”๋“œ ๋ฐœ์ƒ ๊ฐ€๋Šฅ:

| id   | name     |
|------|----------|
| NULL | Alice    |
| NULL | Bob      |
        
  • ๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ ์œ„๋ฐ˜: ํ…Œ์ด๋ธ”์˜ ๊ณ ์œ ์„ฑ์„ ๋ณด์žฅํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  • ๋ ˆ์ฝ”๋“œ ๊ตฌ๋ถ„ ๋ถˆ๊ฐ€: ํŠน์ • ๋ ˆ์ฝ”๋“œ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•  ๋•Œ ์–ด๋–ค ๋ ˆ์ฝ”๋“œ๋ฅผ ๋Œ€์ƒ์œผ๋กœ ํ• ์ง€ ํŒ๋‹จํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

4. ๊ฒฐ๋ก 

  • @Id: JPA์—์„œ ์—”ํ„ฐํ‹ฐ์™€ ํ…Œ์ด๋ธ” ๊ฐ„์˜ ๋งคํ•‘์—์„œ ํ•„์ˆ˜์ ์ธ ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ, Primary Key๋ฅผ ๋ฐ˜๋“œ์‹œ ์ง€์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • @GeneratedValue: Primary Key ๊ฐ’์„ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜์—ฌ ๊ฐœ๋ฐœ์ž์˜ ์ˆ˜๋™ ์„ค์ • ๋ถ€๋‹ด์„ ์ค„์—ฌ์ค๋‹ˆ๋‹ค.
  • ๋‘ ์–ด๋…ธํ…Œ์ด์…˜ ์—†์ด JPA๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ ๋ฌธ์ œ์™€ JPA ๋™์ž‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

@PersistenceContext์˜ ์—ญํ• 

1. @PersistenceContext๋ž€?

@PersistenceContext๋Š” JPA(Java Persistence API)์—์„œ EntityManager๋ฅผ ์ฃผ์ž…ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜์ž…๋‹ˆ๋‹ค.

EntityManager๋Š” JPA์˜ ํ•ต์‹ฌ ๊ฐ์ฒด๋กœ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์ƒํ˜ธ์ž‘์šฉํ•˜๋ฉฐ ์—”ํ„ฐํ‹ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

2. ์ฃผ์š” ์—ญํ• 

  • EntityManager ์ฃผ์ž…: @PersistenceContext๋Š” ์ปจํ…Œ์ด๋„ˆ์—์„œ ๊ด€๋ฆฌ๋˜๋Š” EntityManager๋ฅผ ํ•ด๋‹น ํ•„๋“œ์— ์ฃผ์ž…ํ•ฉ๋‹ˆ๋‹ค.
  • Persistence Context ๊ด€๋ฆฌ: ํŠธ๋žœ์žญ์…˜ ๋ฒ”์œ„ ๋‚ด์—์„œ EntityManager๋ฅผ ๊ด€๋ฆฌํ•˜๋ฉฐ, ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์ž๋™์œผ๋กœ ์—ด๋ฆฌ๊ณ  ๋‹ซํž™๋‹ˆ๋‹ค.
  • Persistence Unit ์ง€์ • ๊ฐ€๋Šฅ: ์—ฌ๋Ÿฌ Persistence Unit์ด ์žˆ์„ ๊ฒฝ์šฐ, unitName ์†์„ฑ์„ ํ†ตํ•ด ํŠน์ • Persistence Unit์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

3. ์‚ฌ์šฉ ์˜ˆ์ œ


import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;

@Repository
public class UserRepository {

    @PersistenceContext
    private EntityManager entityManager;

    public User findUserById(Long id) {
        return entityManager.find(User.class, id); // User ์—”ํ‹ฐํ‹ฐ ์กฐํšŒ
    }

    public void saveUser(User user) {
        entityManager.persist(user); // User ์—”ํ‹ฐํ‹ฐ ์ €์žฅ
    }
}
    

4. ์ฃผ์š” ํŠน์ง•

  • ์ž๋™ ๊ด€๋ฆฌ: JPA ๊ตฌํ˜„์ฒด(Hibernate ๋“ฑ)๊ฐ€ EntityManager์˜ ์ƒ๋ช… ์ฃผ๊ธฐ๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  • ํŠธ๋žœ์žญ์…˜ ๊ธฐ๋ฐ˜ ๋™์ž‘: EntityManager๋Š” ํŠธ๋žœ์žญ์…˜ ๋ฒ”์œ„์—์„œ ์—ด๋ฆฌ๊ณ  ๋‹ซํžˆ๋ฉฐ, ํŠธ๋žœ์žญ์…˜์ด ๋๋‚˜๋ฉด ์ž๋™์œผ๋กœ ์ •๋ฆฌ๋ฉ๋‹ˆ๋‹ค.
  • ์Šคํ”„๋ง ์—ฐ๋™: ์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œํฌ๋Š” @PersistenceContext๋ฅผ ํ†ตํ•ด EntityManager๋ฅผ ์˜์กด์„ฑ์œผ๋กœ ์ฃผ์ž…ํ•ฉ๋‹ˆ๋‹ค.
  • Persistence Unit ์„ ํƒ ๊ฐ€๋Šฅ: ์—ฌ๋Ÿฌ Unit์ด ์žˆ์„ ๊ฒฝ์šฐ ํŠน์ • Unit์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    
    @PersistenceContext(unitName = "myPersistenceUnit")
    private EntityManager entityManager;
                

5. @Autowired์™€์˜ ์ฐจ์ด

์Šคํ”„๋ง์—์„œ @Autowired๋ฅผ ํ†ตํ•ด EntityManager๋ฅผ ์ฃผ์ž…ํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, @PersistenceContext๋Š” JPA ํ‘œ์ค€์— ๋”ฐ๋ฅธ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ‘œ์ค€์„ ๋”ฐ๋ฅด๊ณ ์ž ํ•  ๋•Œ๋Š” @PersistenceContext๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ๋ช…์‹œ์ ์ž…๋‹ˆ๋‹ค.

6. ์„ค์ • ๋ฐ ๋™์ž‘

Spring Boot์—์„œ๋Š” JPA ์„ค์ •์ด ๊ฐ„์†Œํ™”๋˜์–ด ์žˆ์œผ๋ฉฐ, application.properties์— ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ค์ •์„ ์ถ”๊ฐ€ํ•˜๋ฉด EntityManager๊ฐ€ ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค:


spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=1234
spring.jpa.hibernate.ddl-auto=update
    

7. ๊ฒฐ๋ก 

  • @PersistenceContext๋Š” EntityManager๋ฅผ ์ฃผ์ž…๋ฐ›์•„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์ƒํ˜ธ์ž‘์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
  • JPA ํ‘œ์ค€ ๋ฐฉ์‹์œผ๋กœ EntityManager๋ฅผ ๊ด€๋ฆฌํ•˜๋ฉฐ, ์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œํฌ์™€ ์‰ฝ๊ฒŒ ์—ฐ๋™๋ฉ๋‹ˆ๋‹ค.
  • ํŠธ๋žœ์žญ์…˜ ๋ฒ”์œ„ ๋‚ด์—์„œ EntityManager์˜ ์ƒ๋ช… ์ฃผ๊ธฐ๋ฅผ ์ž๋™์œผ๋กœ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

์ด ๊ธ€์ด JPA๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜์—ˆ๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค! ๐Ÿ˜Š


 

 

๐Ÿ”ฅ ํŠธ๋žœ์žญ์…˜๊ณผ ์—”ํ‹ฐํ‹ฐ๋งค๋‹ˆ์ €์˜ ๊ด€๊ณ„

ํŠธ๋žœ์žญ์…˜(Transaction)๊ณผ ์—”ํ‹ฐํ‹ฐ๋งค๋‹ˆ์ €(EntityManager)๋Š” JPA์—์„œ ๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ์„ ๋ณด์žฅํ•˜๊ณ , ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์—”ํ‹ฐํ‹ฐ ๊ฐ„์˜ ์ƒํ˜ธ์ž‘์šฉ์„ ํšจ์œจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ํ•จ๊ป˜ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

1. EntityManager๋ž€?

EntityManager๋Š” JPA์—์„œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ(Persistence Context)๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํ•ต์‹ฌ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€์˜ ์ƒํ˜ธ์ž‘์šฉ ๋ฐ ์—”ํ‹ฐํ‹ฐ์˜ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

  • CRUD ์ž‘์—… ์ˆ˜ํ–‰: persist, find, merge, remove.
  • ์—”ํ‹ฐํ‹ฐ ์ƒํƒœ ์ถ”์  ๋ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ๋™๊ธฐํ™”.
  • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ๊ด€๋ฆฌ.

2. Transaction์ด๋ž€?

Transaction์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—…์˜ ๋…ผ๋ฆฌ์  ๋‹จ์œ„๋กœ, ์ž‘์—…์˜ ์›์ž์„ฑ, ์ผ๊ด€์„ฑ, ๊ฒฉ๋ฆฌ์„ฑ, ์ง€์†์„ฑ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค (ACID ์†์„ฑ).

  • ์ž‘์—… ๋‹จ์œ„๋ฅผ ๊ทธ๋ฃนํ™”ํ•˜์—ฌ ๋ชจ๋‘ ์„ฑ๊ณตํ•˜๊ฑฐ๋‚˜ ๋ชจ๋‘ ์‹คํŒจํ•˜๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
  • EntityManager๋Š” ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ๋งŒ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์ƒํ˜ธ์ž‘์šฉํ•ฉ๋‹ˆ๋‹ค.

3. EntityManager์™€ Transaction์˜ ๊ด€๊ณ„

EntityManager์™€ Transaction์€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ํ†ตํ•ด ์—ฐ๊ฒฐ๋ฉ๋‹ˆ๋‹ค. ์ฃผ์š” ๊ด€๊ณ„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  • EntityManager๋Š” ํŠธ๋žœ์žญ์…˜ ๋ฒ”์œ„ ๋‚ด์—์„œ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.
  • ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘ ์‹œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ํ™œ์„ฑํ™”๋˜๋ฉฐ, ์ปค๋ฐ‹ ๋˜๋Š” ๋กค๋ฐฑ ์‹œ ์ข…๋ฃŒ๋ฉ๋‹ˆ๋‹ค.
  • ํŠธ๋žœ์žญ์…˜ ์—†์ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ณ€๊ฒฝ ์ž‘์—…์ด ์ˆ˜ํ–‰๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

4. ์ฃผ์š” ๋™์ž‘ ์˜ˆ์ œ

ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹ ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ


EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();

try {
    tx.begin(); // ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘
    Member member = new Member();
    member.setName("John Doe");
    em.persist(member); // ์—”ํ‹ฐํ‹ฐ ์ €์žฅ
    tx.commit(); // ํŠธ๋žœ์žญ์…˜ ์ปค๋ฐ‹
} catch (Exception e) {
    tx.rollback(); // ํŠธ๋žœ์žญ์…˜ ๋กค๋ฐฑ
} finally {
    em.close();
}
    

์Šคํ”„๋ง์—์„œ @Transactional ์‚ฌ์šฉ


@Service
public class MemberService {
    @Transactional
    public void createMember(String name) {
        Member member = new Member();
        member.setName(name);
        memberRepository.save(member);
    }
}
    

๐Ÿ”ฅ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ž€ ๋ฌด์—‡์ธ๊ฐ€?

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ(Persistence Context)๋Š” JPA์—์„œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์ €์žฅ์†Œ์ž…๋‹ˆ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์‚ฌ์ด์˜ ์ค‘๊ฐ„ ๊ณ„์ธต์œผ๋กœ, ์—”ํ‹ฐํ‹ฐ์˜ ์ƒํƒœ๋ฅผ ์ถ”์ ํ•˜๊ณ  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ๋™๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.

1. ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ ํŠน์ง•

  • 1์ฐจ ์บ์‹œ: ๋™์ผํ•œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ์กฐํšŒํ•ด๋„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ๋ณ€๊ฒฝ ๊ฐ์ง€(Dirty Checking): ์—”ํ‹ฐํ‹ฐ์˜ ์ƒํƒœ ๋ณ€ํ™”๋ฅผ ๊ฐ์ง€ํ•˜์—ฌ ํŠธ๋žœ์žญ์…˜ ์ปค๋ฐ‹ ์‹œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋ฐ˜์˜ํ•ฉ๋‹ˆ๋‹ค.
  • ์ง€์—ฐ ๋กœ๋”ฉ(Lazy Loading): ํ•„์š”ํ•œ ์‹œ์ ์—๋งŒ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
  • ๋™์ผ์„ฑ ๋ณด์žฅ: ๋™์ผํ•œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ๋‚ด์—์„œ๋Š” ๋™์ผํ•œ ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

2. ์—”ํ‹ฐํ‹ฐ์˜ ์ƒํƒœ

์—”ํ‹ฐํ‹ฐ๋Š” JPA์—์„œ ๋‹ค์Œ ๋„ค ๊ฐ€์ง€ ์ƒํƒœ ์ค‘ ํ•˜๋‚˜๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

  • ๋น„์˜์†(Transient): JPA๊ฐ€ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๋Š” ์ƒํƒœ.
  • ์˜์†(Managed): ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ๊ด€๋ฆฌ๋˜๋Š” ์ƒํƒœ.
  • ์ค€์˜์†(Detached): ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ๋ถ„๋ฆฌ๋œ ์ƒํƒœ.
  • ์‚ญ์ œ(Removed): ์‚ญ์ œ ์ƒํƒœ๋กœ, ํŠธ๋žœ์žญ์…˜ ์ปค๋ฐ‹ ์‹œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์‚ญ์ œ๋จ.

3. ์ฃผ์š” ๊ธฐ๋Šฅ

1์ฐจ ์บ์‹œ

์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ ‘๊ทผ์„ ์ตœ์†Œํ™”ํ•ฉ๋‹ˆ๋‹ค.


Member member1 = em.find(Member.class, 1L); // DB์—์„œ ์กฐํšŒ
Member member2 = em.find(Member.class, 1L); // 1์ฐจ ์บ์‹œ์—์„œ ์กฐํšŒ (์ฟผ๋ฆฌ ๋ฐœ์ƒ X)
    

๋ณ€๊ฒฝ ๊ฐ์ง€

์—”ํ‹ฐํ‹ฐ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ž๋™์œผ๋กœ ๊ฐ์ง€ํ•˜๊ณ  ๋ฐ˜์˜ํ•ฉ๋‹ˆ๋‹ค.


Member member = em.find(Member.class, 1L);
member.setName("Jane Doe"); // ๋ณ€๊ฒฝ ๊ฐ์ง€
em.getTransaction().commit(); // UPDATE ์ฟผ๋ฆฌ ์‹คํ–‰
    

์“ฐ๊ธฐ ์ง€์—ฐ

๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ํŠธ๋žœ์žญ์…˜ ์ปค๋ฐ‹ ์‹œ์ ์— ํ•œ๊บผ๋ฒˆ์— ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋ฐ˜์˜ํ•ฉ๋‹ˆ๋‹ค.


em.persist(member1);
em.persist(member2);
em.getTransaction().commit(); // INSERT ์ฟผ๋ฆฌ ์‹คํ–‰
    

4. ๊ฒฐ๋ก 

  • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋Š” ์—”ํ‹ฐํ‹ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€์˜ ์ƒํ˜ธ์ž‘์šฉ์„ ์ตœ์ ํ™”ํ•ฉ๋‹ˆ๋‹ค.
  • ํŠธ๋žœ์žญ์…˜๊ณผ ๊ฒฐํ•ฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.

 

 

ํŠธ๋žœ์žญ์…˜๊ณผ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ: ๊ฐ™์€ ID๋Š” ๊ฐ™์€ ์—”ํ‹ฐํ‹ฐ๋กœ ์‹๋ณ„

1. ํŠธ๋žœ์žญ์…˜๊ณผ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ

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

1.1 ํŠธ๋žœ์žญ์…˜

  • ํŠธ๋žœ์žญ์…˜์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—…์˜ ๋…ผ๋ฆฌ์  ๋‹จ์œ„์ž…๋‹ˆ๋‹ค.
  • ํŠธ๋žœ์žญ์…˜์ด ์‹œ์ž‘๋˜๋ฉด JPA๋Š” ํ•ด๋‹น ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ ํ•˜๋‚˜์˜ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ด๋ฅผ ํ†ตํ•ด ์—”ํ‹ฐํ‹ฐ๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

1.2 ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ

  • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋Š” ์—”ํ‹ฐํ‹ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„(์บ์‹œ)์œผ๋กœ, ์—”ํ‹ฐํ‹ฐ์˜ ์ƒํƒœ๋ฅผ ์ถ”์ ํ•˜๊ณ  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ๋™๊ธฐํ™”๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • ๋™์ผํ•œ ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ ๋™์ผํ•œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

2. ์ฝ”๋“œ์—์„œ ์ผ์–ด๋‚˜๋Š” ์ฃผ์š” ์ž‘์—…


@Test
@Transactional
@Rollback(false)
public void testMember() throws Exception {
    // given
    Member member = new Member();
    member.setUsername("memberA");

    // when
    Long saveId = memberRepository.save(member);
    Member findMember = memberRepository.find(saveId);

    // then
    Assertions.assertThat(findMember.getId()).isEqualTo(member.getId());
    Assertions.assertThat(findMember.getUsername()).isEqualTo(member.getUsername());
    Assertions.assertThat(findMember).isEqualTo(member);
}
    

2.1 ์ฃผ์š” ์ž‘์—…

  • @Transactional: ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ์—์„œ ํŠธ๋žœ์žญ์…˜์ด ์‹œ์ž‘๋˜๊ณ , JPA๋Š” ํ•˜๋‚˜์˜ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
  • save: memberRepository.save(member)๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด, ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.
  • find: memberRepository.find(saveId)๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด JPA๋Š” ๋จผ์ € ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • Assertions: findMember์™€ member๊ฐ€ ๊ฐ™์€ ์ธ์Šคํ„ด์Šค์ž„์„ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.

3. ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ ๋™์ž‘

3.1 ์—”ํ‹ฐํ‹ฐ ์ €์žฅ (persist)

memberRepository.save(member) ํ˜ธ์ถœ ์‹œ:

  • member ๊ฐ์ฒด๊ฐ€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.
  • ํŠธ๋žœ์žญ์…˜์ด ์ปค๋ฐ‹๋  ๋•Œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.

3.2 ์—”ํ‹ฐํ‹ฐ ์กฐํšŒ (find)

memberRepository.find(saveId) ํ˜ธ์ถœ ์‹œ:

  • JPA๋Š” ๋จผ์ € ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • ๋™์ผํ•œ ID์˜ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์ด๋ฏธ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์กด์žฌํ•˜๋ฉด, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์กฐํšŒ ์—†์ด ์บ์‹œ๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

4. ์ค‘์š”ํ•œ ๊ฐœ๋…: "๊ฐ™์€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ๊ฐ™์€ ID๋Š” ๊ฐ™์€ ์—”ํ‹ฐํ‹ฐ"

  • ๊ฐ™์€ ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ ๊ฐ™์€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ์‚ฌ์šฉ: ํŠธ๋žœ์žญ์…˜์ด ์œ ์ง€๋˜๋ฉฐ, ๊ฐ™์€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ ๋™์ผ์„ฑ ๋ณด์žฅ: ๋™์ผํ•œ ID ๊ฐ’์„ ๊ฐ€์ง„ ์—”ํ‹ฐํ‹ฐ๋Š” ๊ฐ™์€ ๊ฐ์ฒด๋กœ ๊ด€๋ฆฌ๋ฉ๋‹ˆ๋‹ค.
  • ์บ์‹ฑ ํšจ๊ณผ: ๋™์ผํ•œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์—ฌ๋Ÿฌ ๋ฒˆ ์กฐํšŒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

5. Assertions์— ๋Œ€ํ•œ ์„ค๋ช…


Assertions.assertThat(findMember.getId()).isEqualTo(member.getId());
Assertions.assertThat(findMember.getUsername()).isEqualTo(member.getUsername());
Assertions.assertThat(findMember).isEqualTo(member);
    

์œ„ Assertions๋Š” ๋‹ค์Œ์„ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค:

  • ID์™€ Username ๋น„๊ต: findMember์™€ member์˜ ID์™€ Username์ด ๋™์ผํ•ฉ๋‹ˆ๋‹ค.
  • ๊ฐ์ฒด ๋™์ผ์„ฑ ๋น„๊ต: findMember์™€ member๊ฐ€ ๊ฐ™์€ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ๋ฅผ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค.

6. ์˜ˆ์ œ์˜ ํ•ต์‹ฌ ์š”์•ฝ

  • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋Š” ์—”ํ‹ฐํ‹ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์บ์‹œ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
  • 1์ฐจ ์บ์‹œ: ๋™์ผํ•œ ID์˜ ์—”ํ‹ฐํ‹ฐ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์กฐํšŒํ•˜์ง€ ์•Š๊ณ  ์บ์‹œ์—์„œ ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค.
  • ํŠธ๋žœ์žญ์…˜๊ณผ ๊ฒฐํ•ฉ: ๊ฐ™์€ ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ๋Š” ๊ฐ™์€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • ID๋กœ ๊ฐ™์€ ์—”ํ‹ฐํ‹ฐ ์‹๋ณ„: ๊ฐ™์€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ๋‚ด์—์„œ ๋™์ผํ•œ ID๋ฅผ ๊ฐ€์ง„ ์—”ํ‹ฐํ‹ฐ๋Š” ๊ฐ™์€ ๊ฐ์ฒด๋กœ ์ทจ๊ธ‰๋ฉ๋‹ˆ๋‹ค.

7. ๋น„์œ ๋กœ ์ดํ•ดํ•˜๊ธฐ

  • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋Š” ์‚ฌ๋ฌด์‹ค ์บ๋น„๋‹›: ํ•œ ๋ฒˆ ์ €์žฅ๋œ ๋ฌธ์„œ๋Š” ๋™์ผํ•œ ํŠธ๋žœ์žญ์…˜ ๋™์•ˆ ์บ๋น„๋‹›์—์„œ ์ฐพ์•„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • ๊ฐ™์€ ๋ฌธ์„œ๋ผ๋ฉด ๊ฐ™์€ ๋‚ด์šฉ: ID(๋ฌธ์„œ ๋ฒˆํ˜ธ)๊ฐ€ ๊ฐ™์œผ๋ฉด ํ•ญ์ƒ ๊ฐ™์€ ๋ฌธ์„œ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

 

JPA ์—ฐ๊ด€๊ด€๊ณ„ ์ฃผ์ธ

JPA์—์„œ ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ ์„ค์ •

JPA์—์„œ ์—”ํ‹ฐํ‹ฐ ๊ฐ„ ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ์„ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์€ ๊ด€๊ณ„๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์ธก์„ ๋ช…ํ™•ํžˆ ํ•˜๊ธฐ ์œ„ํ•ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜์— ๊ทธ ์ด์œ ๋ฅผ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

1. ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ์˜ ์—ญํ• 

JPA์—์„œ ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ์€ ์™ธ๋ž˜ ํ‚ค(Foreign Key, FK)๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์—”ํ‹ฐํ‹ฐ๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ฃผ์ธ์€ ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋ฐ˜์˜ํ•  ์ฑ…์ž„์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ฃผ์ธ์€ @JoinColumn์„ ํ†ตํ•ด ์™ธ๋ž˜ ํ‚ค๋ฅผ ๋งคํ•‘ํ•ฉ๋‹ˆ๋‹ค.
  • ์ฃผ์ธ์ด ์•„๋‹Œ ์ชฝ(๋น„์ฃผ์ธ)์€ ๋‹จ์ˆœํžˆ ๋งคํ•‘ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜๋Š” ์—ญํ• ๋กœ, ์™ธ๋ž˜ ํ‚ค๋ฅผ ์ง์ ‘ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, Order์™€ Member๊ฐ€ @OneToMany์™€ @ManyToOne ๊ด€๊ณ„๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋‹ค๋ฉด:

  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—๋Š” Order ํ…Œ์ด๋ธ”์— ์™ธ๋ž˜ ํ‚ค๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.
  • JPA์—์„œ๋Š” Order ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ์œผ๋กœ ์„ค์ •๋˜์–ด์•ผ ์™ธ๋ž˜ ํ‚ค๋ฅผ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

2. ์–‘๋ฐฉํ–ฅ ์—ฐ๊ด€๊ด€๊ณ„์™€ ์™ธ๋ž˜ ํ‚ค

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

@Entity
public class Member {
    @OneToMany(mappedBy = "member") // ๋น„์ฃผ์ธ
    private List<Order> orders;
}

@Entity
public class Order {
    @ManyToOne
    @JoinColumn(name = "member_id") // ์ฃผ์ธ
    private Member member;
}
    
  • Order ์—”ํ‹ฐํ‹ฐ๋Š” ์™ธ๋ž˜ ํ‚ค member_id๋ฅผ ์ง์ ‘ ๊ด€๋ฆฌํ•˜๋ฏ€๋กœ ์ฃผ์ธ์ด ๋ฉ๋‹ˆ๋‹ค.
  • Member ์—”ํ‹ฐํ‹ฐ๋Š” mappedBy ์†์„ฑ์„ ํ†ตํ•ด Order์˜ member ํ•„๋“œ์— ์˜ํ•ด ๋งคํ•‘๋œ๋‹ค๋Š” ๊ฒƒ์„ ๋‚˜ํƒ€๋‚ด๋ฉฐ, ๋น„์ฃผ์ธ์œผ๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค.

3. ์—ฐ๊ด€๊ด€๊ณ„ ์ฃผ์ธ์„ ์ž˜๋ชป ์„ค์ •ํ–ˆ์„ ๊ฒฝ์šฐ ๋ฌธ์ œ

์—ฐ๊ด€๊ด€๊ณ„ ์ฃผ์ธ์„ ์ž˜๋ชป ์„ค์ •ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

  • ๋ณ€๊ฒฝ ์‚ฌํ•ญ ๋ฏธ๋ฐ˜์˜: ๋น„์ฃผ์ธ ์ชฝ ์—”ํ‹ฐํ‹ฐ์— ๊ฐ’์„ ์„ค์ •ํ•ด๋„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋ฐ˜์˜๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
Member member = em.find(Member.class, 1L);
Order order = new Order();
member.getOrders().add(order); // ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ฐ˜์˜ ์•ˆ ๋จ
    

์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ•:

Order order = new Order();
order.setMember(member); // ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋ฐ˜์˜๋จ
    
  • ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๊ฒฐ๊ณผ: ๊ฐ์ฒด ๊ฐ„ ์ฐธ์กฐ ์ƒํƒœ์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ƒํƒœ๊ฐ€ ๋ถˆ์ผ์น˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
Member member = em.find(Member.class, 1L);
Order order = new Order();
order.setMember(member); // ์ฃผ์ธ์— ์„ค์ •
member.getOrders().add(order); // ๋น„์ฃผ์ธ๋„ ๋™๊ธฐํ™”
    

4. ์™œ JPA๋Š” ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ์„ ๊ฐ•์ œํ• ๊นŒ?

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋Š” ์™ธ๋ž˜ ํ‚ค๋ฅผ ํ•œ์ชฝ ํ…Œ์ด๋ธ”์—๋งŒ ๋‘๊ธฐ ๋•Œ๋ฌธ์—, ์ด๋ฅผ ๋งคํ•‘ํ•˜๋Š” JPA๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํ•œ์ชฝ๋งŒ ์ฑ…์ž„์„ ๊ฐ–๋„๋ก ๊ฐ•์ œํ•ฉ๋‹ˆ๋‹ค.

์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„๋ฅผ ํ—ˆ์šฉํ•˜๋ฉด์„œ๋„ ๋ฐ์ดํ„ฐ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๋ ค๋ฉด ํ•œ์ชฝ์—์„œ๋งŒ ์™ธ๋ž˜ ํ‚ค๋ฅผ ๋ณ€๊ฒฝํ•˜๋„๋ก ์„ค๊ณ„ํ•ด์•ผ ํ˜ผ๋ž€์„ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

5. ๊ฒฐ๋ก 

์—”ํ‹ฐํ‹ฐ ๊ฐ„ ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ์„ ๋ช…ํ™•ํžˆ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ƒํƒœ์™€ ๊ฐ์ฒด ์ƒํƒœ์˜ ์ผ์น˜๋ฅผ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•ด ํ•„์ˆ˜์ ์ž…๋‹ˆ๋‹ค. ์ฃผ์ธ์„ ์„ค์ •ํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ์ž˜๋ชป ์„ค์ •ํ•˜๋ฉด ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐ˜์˜๋˜์ง€ ์•Š๊ฑฐ๋‚˜ ์ผ๊ด€์„ฑ์ด ๊นจ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ JPA์—์„œ๋Š” ํ•ญ์ƒ ์™ธ๋ž˜ ํ‚ค๋ฅผ ์ง์ ‘ ๊ด€๋ฆฌํ•  ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ฃผ์ธ์œผ๋กœ ์ง€์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.


 

๐Ÿ“ ์ฐธ๊ณ 

 

์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ €์™€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ์ •ํ™•ํ•˜๊ฒŒ ์ดํ•ดํ•ด๋ณด์ž

JPA ๊ณต์‹ ๋ฌธ์„œ์™€ Hibernate ๋ฌธ์„œ๋ฅผ ๋ณด๊ณ  ์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ €์™€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ์ •ํ™•ํ•˜๊ฒŒ ์ดํ•ดํ•˜์ž.

psvm.kr

 

๋Œ“๊ธ€