JPA

JPA ์—”ํ‹ฐํ‹ฐ ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„์—์„œ ์—ฐ๊ด€๊ด€๊ณ„ ์ฃผ์ธ์ด ํ•„์š”ํ•œ ์ด์œ 

devJK93 2024. 12. 9.

๐Ÿ“ JPA ์—ฐ๊ด€ ๊ด€๊ณ„์˜ ์ฃผ์ธ 1

1. ๋ฌธ์ œ ์ƒํ™ฉ: ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„์—์„œ ์™ธ๋ž˜ ํ‚ค ๊ด€๋ฆฌ ์ถฉ๋Œ

์˜ˆ์ œ ์„ค๊ณ„

  • Team๊ณผ Member๋Š” ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„๋กœ ์„ค๊ณ„๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • Team์€ ์—ฌ๋Ÿฌ Member๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์œผ๋ฉฐ, Member๋Š” ํ•˜๋‚˜์˜ Team์— ์†ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ๋Š” Member ํ…Œ์ด๋ธ”์— TEAM_ID๋ผ๋Š” ์™ธ๋ž˜ ํ‚ค๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์ œ ์ฝ”๋“œ

@Entity
public class Team {
    @Id
    @GeneratedValue
    private Long id;

    @OneToMany
    @JoinColumn(name = "TEAM_ID") // Team๋„ ์™ธ๋ž˜ ํ‚ค๋ฅผ ๊ด€๋ฆฌํ•˜๋ ค๊ณ  ์‹œ๋„
    private List<Member> members = new ArrayList<>();
}

@Entity
public class Member {
    @Id
    @GeneratedValue
    private Long id;

    @ManyToOne
    @JoinColumn(name = "TEAM_ID") // Member๋„ ์™ธ๋ž˜ ํ‚ค๋ฅผ ๊ด€๋ฆฌํ•˜๋ ค๊ณ  ์‹œ๋„
    private Team team;
}

2. ์‹ค์ œ ๋™์ž‘: ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„์—์„œ ์™ธ๋ž˜ ํ‚ค ๋ณ€๊ฒฝ

1. Team ์—”ํ‹ฐํ‹ฐ์—์„œ ๋ฉค๋ฒ„ ์ถ”๊ฐ€

Team team = new Team();
Member member = new Member();

// Team์—์„œ ๋ฉค๋ฒ„ ์ถ”๊ฐ€
team.getMembers().add(member);

Team์—์„œ ๋ฉค๋ฒ„๋ฅผ ์ถ”๊ฐ€ํ–ˆ์ง€๋งŒ, ์™ธ๋ž˜ ํ‚ค TEAM_ID๊ฐ€ ์–ด๋–ป๊ฒŒ ์„ค์ •๋ ์ง€ ๋ช…ํ™•ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

2. Member ์—”ํ‹ฐํ‹ฐ์—์„œ ํŒ€ ์„ค์ •

member.setTeam(team);

Member์—์„œ ํŒ€์„ ์„ค์ •ํ–ˆ์ง€๋งŒ, TEAM_ID๊ฐ€ ์–ด๋–ป๊ฒŒ ๋ณ€๊ฒฝ๋ ์ง€ ๋ช…ํ™•ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‘ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ๋ชจ๋‘ ์™ธ๋ž˜ ํ‚ค๋ฅผ ๊ด€๋ฆฌํ•˜๋ ค ํ•˜๋ฉด ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

3. JPA์˜ ๋ฌธ์ œ: ์™ธ๋ž˜ ํ‚ค ์ถฉ๋Œ

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

  • ๋‘ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ๋™์‹œ์— ์™ธ๋ž˜ ํ‚ค๋ฅผ ๋ณ€๊ฒฝํ•˜๋ ค ํ•˜๋ฉด ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•˜๊ฑฐ๋‚˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์†์‹ค๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ฃผ์ธ์„ ๋ช…ํ™•ํžˆ ์ง€์ •ํ•˜๋ฉด JPA๋Š” ์ฃผ์ธ๋งŒ ์—…๋ฐ์ดํŠธํ•˜๊ณ , ๋น„์ฃผ์ธ์€ ๋ฐ์ดํ„ฐ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๋Š” ์—ญํ• ๋งŒ ํ•ฉ๋‹ˆ๋‹ค.

4. ํ•ด๊ฒฐ: ๊ด€๊ณ„์˜ ์ฃผ์ธ์„ ๋ช…ํ™•ํžˆ ์ง€์ •

Member ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ฃผ์ธ(Owner)์œผ๋กœ ์ง€์ •ํ•˜๊ณ , Team ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋น„์ฃผ์ธ(Non-Owner)์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

์™ธ๋ž˜ ํ‚ค๋ฅผ Member์—์„œ๋งŒ ๊ด€๋ฆฌํ•˜๊ณ , Team์—์„œ๋Š” ์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ˆ˜์ •๋œ ์„ค๊ณ„

@Entity
public class Team {
    @Id
    @GeneratedValue
    private Long id;

    private String name;

    @OneToMany(mappedBy = "team") // ๋น„์ฃผ์ธ, ์™ธ๋ž˜ ํ‚ค๋Š” Member๊ฐ€ ๊ด€๋ฆฌ
    private List<Member> members = new ArrayList<>();
}

@Entity
public class Member {
    @Id
    @GeneratedValue
    private Long id;

    private String name;

    @ManyToOne
    @JoinColumn(name = "TEAM_ID") // ์ฃผ์ธ, ์™ธ๋ž˜ ํ‚ค ๊ด€๋ฆฌ
    private Team team;
}

5. ์˜ˆ์‹œ: ์ฃผ์ธ๊ณผ ๋น„์ฃผ์ธ์˜ ์ฐจ์ด

Team์—์„œ ๋ฉค๋ฒ„ ์ถ”๊ฐ€

Team team = new Team();
Member member = new Member();

// Team์—์„œ ๋ฉค๋ฒ„ ์ถ”๊ฐ€
team.getMembers().add(member);

// Member์—์„œ ํŒ€ ์„ค์ • (์™ธ๋ž˜ ํ‚ค ๊ด€๋ฆฌ)
member.setTeam(team);

em.persist(team);
em.persist(member);

์‹ค์ œ ์ฟผ๋ฆฌ

INSERT INTO TEAM (id, name) VALUES (?, ?);
INSERT INTO MEMBER (id, name, TEAM_ID) VALUES (?, ?, ?);

6. ์™œ ์™ธ๋ž˜ ํ‚ค๋ฅผ ์ฃผ์ธ์ด ๊ด€๋ฆฌํ•ด์•ผ ํ•˜๋Š”๊ฐ€?

  • ํ•˜๋‚˜์˜ ์ฃผ์ฒด๊ฐ€ ๊ด€๋ฆฌํ•ด์•ผ ๋ฐ์ดํ„ฐ ์ผ๊ด€์„ฑ์ด ์œ ์ง€๋จ:
    • ๋‘ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ๋™์‹œ์— ์™ธ๋ž˜ ํ‚ค๋ฅผ ๋ณ€๊ฒฝํ•˜๋ ค ํ•˜๋ฉด ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•˜๊ฑฐ๋‚˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์†์‹ค๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • JPA์˜ ๋™์ž‘ ๋ฐฉ์‹๊ณผ ์ผ์น˜:
    • JPA๋Š” ๊ด€๊ณ„์˜ ์ฃผ์ธ๋งŒ์ด ์™ธ๋ž˜ ํ‚ค๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
    • ๋น„์ฃผ์ธ์€ ๋‹จ์ˆœํžˆ ์—ฐ๊ด€ ๊ด€๊ณ„๋ฅผ ์ฝ๊ฑฐ๋‚˜ ์กฐํšŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

7. ๊ฒฐ๋ก 

์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„์—์„œ ์—ฐ๊ด€ ๊ด€๊ณ„์˜ ์ฃผ์ธ์„ ๋ช…ํ™•ํžˆ ์ง€์ •ํ•˜๋Š” ์ด์œ ๋Š”:

  • ์™ธ๋ž˜ ํ‚ค ์ถฉ๋Œ ๋ฐฉ์ง€: ํ•˜๋‚˜์˜ ์—”ํ‹ฐํ‹ฐ๋งŒ ์™ธ๋ž˜ ํ‚ค๋ฅผ ๊ด€๋ฆฌํ•˜๋„๋ก ํ•˜์—ฌ ๋ฐ์ดํ„ฐ ์ถฉ๋Œ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  • JPA์˜ ๋ช…ํ™•ํ•œ ์—ญํ•  ๋ถ„๋‹ด: ์ฃผ์ธ์€ ์™ธ๋ž˜ ํ‚ค๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ , ๋น„์ฃผ์ธ์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ธฐ๋งŒ ํ•˜๋„๋ก ์„ค๊ณ„ํ•ฉ๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ ์ฃผ์ธ๊ณผ ๋น„์ฃผ์ธ์„ ๋ช…ํ™•ํžˆ ๋‚˜๋ˆ„๋ฉด, JPA๊ฐ€ ์ผ๊ด€๋œ ๋ฐฉ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

 


๐Ÿ“ JPA ์—ฐ๊ด€ ๊ด€๊ณ„์˜ ์ฃผ์ธ 2

ํ•ต์‹ฌ ๊ฐœ๋…

"์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„์—์„œ ํ•˜๋‚˜์˜ ์—”ํ‹ฐํ‹ฐ๋งŒ ์™ธ๋ž˜ ํ‚ค(FK)๋ฅผ ๊ด€๋ฆฌํ•ด์•ผ ํ•˜๋ฉฐ, ๊ทธ ์—”ํ‹ฐํ‹ฐ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”์—์„œ ์‹ค์ œ๋กœ ์™ธ๋ž˜ ํ‚ค๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ํ…Œ์ด๋ธ”์— ๋งคํ•‘๋œ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์—ฐ๊ด€ ๊ด€๊ณ„์˜ ์ฃผ์ธ์ด ๋œ๋‹ค."

์™œ ์ด๋Ÿฐ ๊ทœ์น™์ด ํ•„์š”ํ• ๊นŒ?

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

์ฃผ์ธ๊ณผ ๋น„์ฃผ์ธ์˜ ์—ญํ• 

  • ์ฃผ์ธ (Owner):
    • ์™ธ๋ž˜ ํ‚ค๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์—”ํ‹ฐํ‹ฐ.
    • @JoinColumn์„ ์‚ฌ์šฉํ•˜์—ฌ ์™ธ๋ž˜ ํ‚ค๋ฅผ ๋งคํ•‘ํ•˜๊ณ , JPA๊ฐ€ ์™ธ๋ž˜ ํ‚ค๋ฅผ ๊ด€๋ฆฌํ•˜๋„๋ก ์„ค์ •.
  • ๋น„์ฃผ์ธ (Non-Owner):
    • ์™ธ๋ž˜ ํ‚ค๋ฅผ ์ง์ ‘ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๋Š” ์—”ํ‹ฐํ‹ฐ.
    • mappedBy๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฃผ์ธ์„ ์ง€์ •ํ•˜๊ณ , ์—ฐ๊ด€ ๊ด€๊ณ„๋ฅผ ์ฝ๊ธฐ๋งŒ ๊ฐ€๋Šฅ.

์˜ˆ์‹œ

ํ…Œ์ด๋ธ” ๊ตฌ์กฐ

  • TEAM:
    • TEAM_ID (PK)
    • NAME
  • MEMBER:
    • MEMBER_ID (PK)
    • NAME
    • TEAM_ID (FK)

์—”ํ‹ฐํ‹ฐ ์„ค๊ณ„

@Entity
public class Team {
    @Id
    @GeneratedValue
    private Long id;

    private String name;

    @OneToMany(mappedBy = "team") // ๋น„์ฃผ์ธ
    private List<Member> members = new ArrayList<>();
}

@Entity
public class Member {
    @Id
    @GeneratedValue
    private Long id;

    private String name;

    @ManyToOne
    @JoinColumn(name = "TEAM_ID") // ์ฃผ์ธ
    private Team team;
}

์ •๋ฆฌ

  • ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„์—์„œ๋Š” ๋ฐ˜๋“œ์‹œ ํ•˜๋‚˜์˜ ์—”ํ‹ฐํ‹ฐ๋งŒ ์™ธ๋ž˜ ํ‚ค๋ฅผ ๊ด€๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ์™ธ๋ž˜ ํ‚ค๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ํ…Œ์ด๋ธ”์— ๋งคํ•‘๋œ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์—ฐ๊ด€ ๊ด€๊ณ„์˜ ์ฃผ์ธ์ด ๋˜๋Š” ๊ฒƒ์ด ์ž์—ฐ์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค.
  • JPA๋Š” ์—ฐ๊ด€ ๊ด€๊ณ„์˜ ์ฃผ์ธ๋งŒ ์™ธ๋ž˜ ํ‚ค๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๊ณ , ๋น„์ฃผ์ธ์€ ์ฝ๊ธฐ๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

์ด ๊ทœ์น™์„ ๋”ฐ๋ฅด๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ๊ฐ์ฒด ๊ฐ„์˜ ๋งคํ•‘์ด ๋ช…ํ™•ํ•˜๊ณ  ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค! ๐Ÿ˜Š


๐Ÿ“™ ๊ฐ์ฒด์™€ ํ…Œ์ด๋ธ”์˜ ๊ด€๊ณ„ ์ฐจ์ด

1. ํ…Œ์ด๋ธ”๊ณผ ๊ฐ์ฒด์˜ ๊ด€๊ณ„ ์ฐจ์ด

ํ…Œ์ด๋ธ” ์„ธ๊ณ„

  • ํ…Œ์ด๋ธ”์—์„œ๋Š” ํ•˜๋‚˜์˜ ์™ธ๋ž˜ ํ‚ค(FK)๋งŒ์œผ๋กœ ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„๋ฅผ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์™ธ๋ž˜ ํ‚ค๋Š” ํ•œ์ชฝ ํ…Œ์ด๋ธ”์—๋งŒ ์กด์žฌํ•˜๋ฉฐ, ๋‹ค๋ฅธ ์ชฝ ํ…Œ์ด๋ธ”์€ ์ด๋ฅผ ์ฐธ์กฐํ•˜์—ฌ ๊ด€๊ณ„๋ฅผ ๋งบ์Šต๋‹ˆ๋‹ค.

์˜ˆ: Member ํ…Œ์ด๋ธ”์— TEAM_ID๋ผ๋Š” ์™ธ๋ž˜ ํ‚ค๊ฐ€ ์žˆ๋‹ค๋ฉด, ์ด ์™ธ๋ž˜ ํ‚ค๋งŒ์œผ๋กœ Member๊ฐ€ Team์„ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๊ณ , ๋ฐ˜๋Œ€๋กœ Team์—์„œ Member๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ์ฒด ์„ธ๊ณ„

  • ๊ฐ์ฒด์—์„œ๋Š” ๊ด€๊ณ„๋ฅผ ์–‘๋ฐฉํ–ฅ์œผ๋กœ ํ‘œํ˜„ํ•˜๋ ค๋ฉด, ๊ฐ ๊ฐ์ฒด๊ฐ€ ์„œ๋กœ๋ฅผ ์ฐธ์กฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ฐ์ฒด๋Š” ์™ธ๋ž˜ ํ‚ค๋ฅผ ์ง์ ‘ ๊ฐ€์ง€์ง€ ์•Š์œผ๋ฉฐ, ๋Œ€์‹  ์ฐธ์กฐ๋ฅผ ์œ„ํ•œ ํ•„๋“œ๋ฅผ ํ†ตํ•ด ๊ด€๊ณ„๋ฅผ ํ‘œํ˜„ํ•ฉ๋‹ˆ๋‹ค.
  • ๋”ฐ๋ผ์„œ ๊ฐ์ฒด ๊ฐ„์˜ ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„๋Š” ๋‹จ๋ฐฉํ–ฅ ๊ด€๊ณ„ ๋‘ ๊ฐœ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ์Šต๋‹ˆ๋‹ค:
    • Member ๊ฐ์ฒด๊ฐ€ Team ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๊ด€๊ณ„.
    • Team ๊ฐ์ฒด๊ฐ€ Member ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๊ด€๊ณ„.

2. ์˜ˆ์ œ

ํ…Œ์ด๋ธ” ์„ค๊ณ„

    • TEAM ํ…Œ์ด๋ธ”:
TEAM_ID   NAME
----------------
1         Development
2         Marketing
    • MEMBER ํ…Œ์ด๋ธ”:
MEMBER_ID   NAME       TEAM_ID (FK)
------------------------------------
101         Alice      1
102         Bob        1
103         Carol      2

๊ฐ์ฒด ์„ค๊ณ„

@Entity
public class Team {
    @Id
    @GeneratedValue
    private Long id;

    private String name;

    @OneToMany(mappedBy = "team") // Team์—์„œ Member๋ฅผ ์ฐธ์กฐ
    private List<Member> members = new ArrayList<>();
}

@Entity
public class Member {
    @Id
    @GeneratedValue
    private Long id;

    private String name;

    @ManyToOne
    @JoinColumn(name = "TEAM_ID") // Member์—์„œ Team์„ ์ฐธ์กฐ
    private Team team;
}

3. ์™œ ๊ฐ์ฒด๋Š” ๋‹จ๋ฐฉํ–ฅ ์ฐธ์กฐ ๋‘ ๊ฐœ๋กœ ์—ฐ๊ฒฐ๋˜๋Š”๊ฐ€?

  • ๊ฐ์ฒด๋Š” ์™ธ๋ž˜ ํ‚ค๋ฅผ ์ง์ ‘ ๊ฐ€์ง€์ง€ ์•Š๋Š”๋‹ค:
    • ๊ฐ์ฒด๋Š” ํ…Œ์ด๋ธ”์ฒ˜๋Ÿผ ์™ธ๋ž˜ ํ‚ค๋ฅผ ๋ฌผ๋ฆฌ์ ์œผ๋กœ ๊ฐ€์ง€์ง€ ์•Š๊ณ , ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๋Š” ํ•„๋“œ๋ฅผ ํ†ตํ•ด ๊ด€๊ณ„๋ฅผ ํ‘œํ˜„ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ฐ์ฒด๋Š” ๋ฐฉํ–ฅ์„ฑ์„ ๊ฐ€์ง„ ์ฐธ์กฐ๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค:
    • ๊ฐ์ฒด๋Š” ํ…Œ์ด๋ธ”์ฒ˜๋Ÿผ ์–‘๋ฐฉํ–ฅ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ํƒ์ƒ‰ํ•  ์ˆ˜ ์žˆ๋Š” ๊ตฌ์กฐ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.
    • Member๊ฐ€ Team์„ ์ฐธ์กฐํ•˜๋ ค๋ฉด Member์— team ํ•„๋“œ๊ฐ€ ์žˆ์–ด์•ผ ํ•˜๊ณ , Team์ด Member๋ฅผ ์ฐธ์กฐํ•˜๋ ค๋ฉด Team์— members ํ•„๋“œ๊ฐ€ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ํ…Œ์ด๋ธ”์˜ FK๋Š” ๋‹จ์ผ ํ•„๋“œ๋กœ ๋ชจ๋“  ๋ฐฉํ–ฅ์„ ํ•ด๊ฒฐ:
    • ํ…Œ์ด๋ธ”์€ JOIN์„ ์‚ฌ์šฉํ•˜์—ฌ ์–‘๋ฐฉํ–ฅ ํƒ์ƒ‰์ด ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ๊ฐ์ฒด๋Š” ์ด๋ฅผ ๋ณ„๋„๋กœ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

4. ๊ฐ์ฒด์™€ ํ…Œ์ด๋ธ” ๊ฐ„์˜ ๊ด€๊ณ„ ๋น„๊ต

ํ…Œ์ด๋ธ” ๊ด€์ 

TEAM (1) ---- FK (TEAM_ID) ----> MEMBER (N)

๊ฐ์ฒด ๊ด€์ 

Team --> members: List  (๋‹จ๋ฐฉํ–ฅ)
Member --> team: Team           (๋‹จ๋ฐฉํ–ฅ)

๋‘ ๊ฐœ์˜ ๋‹จ๋ฐฉํ–ฅ ์ฐธ์กฐ๋ฅผ ํ•ฉ์ณ์„œ ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜๋„๋ก ์„ค๊ณ„ํ•ฉ๋‹ˆ๋‹ค.

5. ์š”์•ฝ

  • ํ…Œ์ด๋ธ” ์„ธ๊ณ„: ์™ธ๋ž˜ ํ‚ค ํ•˜๋‚˜๋งŒ์œผ๋กœ ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„๋ฅผ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๊ฐ์ฒด ์„ธ๊ณ„: ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„๋ฅผ ํ‘œํ˜„ํ•˜๋ ค๋ฉด ๊ฐ ๊ฐ์ฒด์— ์ƒ๋Œ€ ๊ฐ์ฒด์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ๋ณ„๋„๋กœ ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋ฏ€๋กœ, ๋‹จ๋ฐฉํ–ฅ ๊ด€๊ณ„ ๋‘ ๊ฐœ๋กœ ์—ฐ๊ฒฐ๋ฉ๋‹ˆ๋‹ค.
  • ๊ฐ์ฒด ์„ธ๊ณ„์˜ ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„๋Š” ์‚ฌ์‹ค์ƒ ๋‹จ๋ฐฉํ–ฅ ๊ด€๊ณ„ ๋‘ ๊ฐœ๋ฅผ ํ•ฉ์นœ ๊ฒƒ์ด๋ผ๊ณ  ์ดํ•ดํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์ด ๊ฐœ๋…์„ ์•Œ๋ฉด ๊ฐ์ฒด ์„ค๊ณ„์™€ ํ…Œ์ด๋ธ” ์„ค๊ณ„๋ฅผ ์—ฐ๊ฒฐํ•˜์—ฌ ๋” ๋ช…ํ™•ํžˆ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค! ๐Ÿ˜Š


์œ„์™€ ๊ฐ™์€ ์ด์œ ๋กœ ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ์ด ํ•„์š”ํ•˜๋‹ค.

 

๐Ÿ“ ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ์ด ํ•„์š”ํ•œ ์ด์œ 

1. ๊ฐ์ฒด์™€ ํ…Œ์ด๋ธ”์˜ ์ฐจ์ด๋กœ ์ธํ•ด ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ

1. ํ…Œ์ด๋ธ”์—์„œ์˜ ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„

  • ํ…Œ์ด๋ธ”์—์„œ๋Š” ์™ธ๋ž˜ ํ‚ค(FK) ํ•˜๋‚˜๋กœ ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„๋ฅผ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • SQL์—์„œ JOIN์„ ์‚ฌ์šฉํ•˜๋ฉด ์–‘์ชฝ ๋ฐฉํ–ฅ์œผ๋กœ ํƒ์ƒ‰์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค:
    • SELECT * FROM MEMBER WHERE TEAM_ID = ?Member์—์„œ Team์œผ๋กœ ํƒ์ƒ‰
    • SELECT * FROM TEAM T JOIN MEMBER M ON T.TEAM_ID = M.TEAM_IDTeam์—์„œ Member๋กœ ํƒ์ƒ‰

2. ๊ฐ์ฒด์—์„œ์˜ ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„

  • ๊ฐ์ฒด์—์„œ๋Š” ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„๋ฅผ ๊ตฌ์„ฑํ•˜๋ ค๋ฉด, ๋‘ ๊ฐ์ฒด๊ฐ€ ์„œ๋กœ๋ฅผ ์ฐธ์กฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:
    • Member ๊ฐ์ฒด๊ฐ€ Team ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐ (Member → Team)
    • Team ๊ฐ์ฒด๊ฐ€ Member ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐ (Team → Member)
  • ๊ทธ๋Ÿฌ๋‚˜ JPA๋Š” ํ…Œ์ด๋ธ”์— ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ฑฐ๋‚˜ ์™ธ๋ž˜ ํ‚ค๋ฅผ ๊ด€๋ฆฌํ•ด์•ผ ํ•˜๋Š”๋ฐ, ์–‘์ชฝ ๋ชจ๋‘์—์„œ ์™ธ๋ž˜ ํ‚ค๋ฅผ ๊ด€๋ฆฌํ•˜๋ ค๊ณ  ํ•˜๋ฉด ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

2. ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ์ด ํ•„์š”ํ•œ ์ด์œ 

1. ๊ฐ์ฒด์˜ ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„๋Š” ๋‹จ๋ฐฉํ–ฅ 2๊ฐœ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค

  • ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„๋ฅผ ๊ตฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด Member์™€ Team์€ ์„œ๋กœ๋ฅผ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค.
  • ๊ทธ๋Ÿฌ๋‚˜ ํ•˜๋‚˜์˜ ์™ธ๋ž˜ ํ‚ค๋Š” ํ•˜๋‚˜์˜ ์ฃผ์ฒด์— ์˜ํ•ด ๊ด€๋ฆฌ๋˜์–ด์•ผ ๋ฐ์ดํ„ฐ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

2. ์™ธ๋ž˜ ํ‚ค๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์ฑ…์ž„์„ ํ•˜๋‚˜๋กœ ํ†ตํ•ฉํ•ด์•ผ ํ•œ๋‹ค

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

3. ์ฃผ์ธ๋งŒ ์™ธ๋ž˜ ํ‚ค๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค

  • JPA์—์„œ ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ๋งŒ ์™ธ๋ž˜ ํ‚ค๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ฑฐ๋‚˜ ์ €์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋ฐ˜๋ฉด, ๋น„์ฃผ์ธ์€ ๊ด€๊ณ„๋ฅผ ์ฝ๊ธฐ๋งŒ ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—๋Š” ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

3. ์˜ˆ์‹œ

์ž˜๋ชป๋œ ์—ฐ๊ด€๊ด€๊ณ„ ์„ค๊ณ„

@Entity
public class Team {
    @OneToMany
    @JoinColumn(name = "TEAM_ID") // Team๋„ ์™ธ๋ž˜ ํ‚ค๋ฅผ ๊ด€๋ฆฌ
    private List<Member> members;
}

@Entity
public class Member {
    @ManyToOne
    @JoinColumn(name = "TEAM_ID") // Member๋„ ์™ธ๋ž˜ ํ‚ค๋ฅผ ๊ด€๋ฆฌ
    private Team team;
}

์˜ฌ๋ฐ”๋ฅธ ์—ฐ๊ด€๊ด€๊ณ„ ์„ค๊ณ„

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

@Entity
public class Member {
    @ManyToOne
    @JoinColumn(name = "TEAM_ID") // ์ฃผ์ธ
    private Team team;
}

4. ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ์ด ์—†์œผ๋ฉด ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ

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

5. ๊ฒฐ๋ก 

๊ฐ์ฒด์™€ ํ…Œ์ด๋ธ”์˜ ๊ด€๊ณ„ ํ‘œํ˜„ ์ฐจ์ด๋กœ ์ธํ•ด JPA๋Š” ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ์„ ๋„์ž…ํ•ฉ๋‹ˆ๋‹ค.

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

๋”ฐ๋ผ์„œ, "์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ์€ ๊ฐ์ฒด-ํ…Œ์ด๋ธ” ๊ฐ„์˜ ๊ด€๊ณ„ ์ฐจ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋„์ž…๋œ ๊ฐœ๋…์ด๋‹ค"๋ผ๊ณ  ์ดํ•ดํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๐Ÿ˜Š


package jpashop.jpaorder.domain;

import javax.persistence.*;

@Entity
public class Member {

  @Id @GeneratedValue
  @Column(name = "MEMBER_ID")
  private Long id;
  private String name;
  private String city;
  private String street;
  private String zipcode;

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "TEAM_ID")
  private Team team;

  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;
  }

  public String getCity() {
    return city;
  }

  public void setCity(String city) {
    this.city = city;
  }

  public String getStreet() {
    return street;
  }

  public void setStreet(String street) {
    this.street = street;
  }

  public String getZipcode() {
    return zipcode;
  }

  public void setZipcode(String zipcode) {
    this.zipcode = zipcode;
  }

  public Team getTeam() {
    return team;
  }

  public void setTeam(Team team) {
    this.team = team;
  }

  /* ==์—ฐ๊ด€๊ด€๊ณ„ ํŽธ์˜ ๋ฉ”์„œ๋“œ== */
  public void changeTeam(Team team) {
    this.team = team;
    team.getMembers().add(this);
  }
}
package jpashop.jpaorder.domain;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
public class Team {

  @Id @GeneratedValue
  @Column(name = "TEAM_ID")
  private Long id;
  private String name;

  @OneToMany(mappedBy = "team")
  private List<Member> members = new ArrayList<>();

  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;
  }

  public List<Member> getMembers() {
    return members;
  }

  public void setMembers(List<Member> members) {
    this.members = members;
  }

  /* ==์—ฐ๊ด€๊ด€๊ณ„ ํŽธ์˜ ๋ฉ”์„œ๋“œ== */
  public void addMember(Member member) {
    members.add(member);
    member.setTeam(this);
  }
}
package jpashop.jpaorder;

import jpashop.jpaorder.domain.Member;
import jpashop.jpaorder.domain.Team;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import java.util.List;

public class JpaMain {
  public static void main(String[] args) {
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpaorder");
    EntityManager em = emf.createEntityManager();
    EntityTransaction tx = em.getTransaction();
    tx.begin();

    try {

      Team team = new Team();
      team.setName("teamA");

      Member member1 = new Member();
      member1.setName("member1");

      Member member2 = new Member();
      member2.setName("member2");

      team.addMember(member1);
      team.addMember(member2);

      em.persist(member1);
      em.persist(member2);
      em.persist(team);

      List<Member> members1 = team.getMembers();
      for (Member member : members1) {
        System.out.println(member.getName());
      }

//      em.flush();
//      em.clear();

//      Team findTeam = em.find(Team.class, team.getId());
//      List<Member> members = findTeam.getMembers();
//      for (Member member : members) {
//        System.out.println("member.getName() = " + member.getName());
//      }

      tx.commit();
    } catch (Exception e) {
      tx.rollback();
    } finally {
      em.close();
      emf.close();
    }
  }
}

 

โ“ team์— ์ด๋ฏธ member1, 2 ๊ฐ€ ๋‹ค add ๋œ ์ƒํƒœ๋กœ persist ๋˜์ž–์•„ ๊ทผ๋ฐ ์ด๋•Œ team์—๋Š” PK๊ฐ€ ์—†์–ด์„œ member1,2 ์˜ FK๊ฐ€ ์„ธํŒ…์ด ์•ˆ๋˜๋Š”๋ฐ team์ด persist ํ•˜๋ฉด PK๊ฐ€ ์ƒ๊ธฐ๋‹ˆ๊น ๊ทธ๋•Œ member1,2 ์˜ FK๊ฐ€ ์—…๋ฐ์ดํŠธ ๋˜๋Š”๊ฑด๊ฐ€?

๋„ค, ์ •ํ™•ํžˆ ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค.

team์ด persist๋˜์–ด PK๊ฐ€ ์ƒ์„ฑ๋˜๋ฉด, ๊ทธ ์‹œ์ ์— JPA๊ฐ€ member1๊ณผ member2์˜ ์™ธ๋ž˜ ํ‚ค(FK)๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ˜ JPA ์—ฐ๊ด€ ๊ด€๊ณ„์—์„œ FK ์—…๋ฐ์ดํŠธ ๊ณผ์ •

๋™์ž‘ ๊ณผ์ •

  1. team.addMember(member1) ํ˜ธ์ถœ
    • ์—ฐ๊ด€๊ด€๊ณ„ ํŽธ์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด member1์˜ team ํ•„๋“œ๊ฐ€ team์„ ์ฐธ์กฐํ•˜๋„๋ก ์„ค์ •๋ฉ๋‹ˆ๋‹ค.
    • ์ด ์‹œ์ ์—์„œ๋Š” team ๊ฐ์ฒด์˜ id ๊ฐ’(PK)์ด ์•„์ง ์—†์œผ๋ฏ€๋กœ, ์™ธ๋ž˜ ํ‚ค๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์€ ์ƒํƒœ์ž…๋‹ˆ๋‹ค.
  2. em.persist(member1) ํ˜ธ์ถœ
    • JPA๋Š” member1์„ ์˜์†ํ™”ํ•˜๊ณ  Member ํ…Œ์ด๋ธ”์— INSERT ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
    • ํ•˜์ง€๋งŒ TEAM_ID ๊ฐ’(PK)์ด ์•„์ง team์— ์—†์œผ๋ฏ€๋กœ, TEAM_ID๋Š” NULL๋กœ ์‚ฝ์ž…๋ฉ๋‹ˆ๋‹ค.
  3. em.persist(team) ํ˜ธ์ถœ
    • team์ด ์˜์†ํ™”๋˜๋ฉด์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅ๋˜๊ณ , team.id ๊ฐ’(PK)์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.
  4. ํ”Œ๋Ÿฌ์‹œ(Flush)
    • em.flush() ๋˜๋Š” ํŠธ๋žœ์žญ์…˜ ์ปค๋ฐ‹ ์‹œ์ ์— JPA๋Š” team.id ๊ฐ’์„ ์ฐธ์กฐํ•˜์—ฌ member1๊ณผ member2์˜ TEAM_ID๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” UPDATE ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

๋กœ๊ทธ ๋ถ„์„ ์˜ˆ์‹œ

1. INSERT ์ฟผ๋ฆฌ (Member ํ…Œ์ด๋ธ”)

INSERT INTO Member (name, city, street, zipcode, TEAM_ID) VALUES ('member1', NULL, NULL, NULL, NULL);
INSERT INTO Member (name, city, street, zipcode, TEAM_ID) VALUES ('member2', NULL, NULL, NULL, NULL);

2. INSERT ์ฟผ๋ฆฌ (Team ํ…Œ์ด๋ธ”)

INSERT INTO Team (name) VALUES ('teamA');

3. UPDATE ์ฟผ๋ฆฌ (Member ํ…Œ์ด๋ธ”)

UPDATE Member SET TEAM_ID = 1 WHERE MEMBER_ID = 1;
UPDATE Member SET TEAM_ID = 1 WHERE MEMBER_ID = 2;

์™œ ์ด๋ ‡๊ฒŒ ๋™์ž‘ํ• ๊นŒ?

  • IDENTITY ์ „๋žต์˜ ํŠน์„ฑ:
    • team.id๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์ž๋™ ์ƒ์„ฑ๋˜๋ฉฐ, persist ์‹œ์ ์—๋งŒ ๊ฐ’์„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ๋”ฐ๋ผ์„œ, team์ด ๋จผ์ € persist๋˜์ง€ ์•Š์œผ๋ฉด member1๊ณผ member2๋Š” ์˜ฌ๋ฐ”๋ฅธ TEAM_ID ๊ฐ’์„ ์„ค์ •ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  • JPA์˜ ํ”Œ๋Ÿฌ์‹œ ๋™์ž‘:
    • JPA๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ ๋ณ€๊ฒฝ ๋‚ด์šฉ์„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋™๊ธฐํ™”ํ•  ๋•Œ, ์—”ํ‹ฐํ‹ฐ ๊ฐ„์˜ ์—ฐ๊ด€๊ด€๊ณ„๋ฅผ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
    • team.id๊ฐ€ ์ƒ์„ฑ๋œ ์ดํ›„, JPA๋Š” ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ(Member.team)์— ์„ค์ •๋œ ๊ฐ’์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์™ธ๋ž˜ ํ‚ค๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.

์ฝ”๋“œ ๊ฐœ์„  ๋ฐฉ๋ฒ•

1. cascade ์˜ต์…˜ ํ™œ์šฉ

@OneToMany(mappedBy = "team", cascade = CascadeType.PERSIST)
private List<Member> members = new ArrayList<>();

cascade = CascadeType.PERSIST๋ฅผ ์„ค์ •ํ•˜๋ฉด, team.persist ์‹œ member1๊ณผ member2๋„ ์ž๋™์œผ๋กœ persist๋ฉ๋‹ˆ๋‹ค.

2. persist ์ˆœ์„œ ๋ณ€๊ฒฝ

em.persist(team); // ๋จผ์ € team์„ ์ €์žฅ
em.persist(member1);
em.persist(member2);

team์„ ๋จผ์ € persistํ•œ ํ›„, member1๊ณผ member2๋ฅผ persistํ•˜๋ฉด UPDATE ์ฟผ๋ฆฌ๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๋ก 

team์ด persist๋˜๊ธฐ ์ „์—๋Š” team.id ๊ฐ’์ด ์—†์œผ๋ฏ€๋กœ, member1๊ณผ member2์˜ TEAM_ID๋Š” ์„ค์ •๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

team์ด persist๋˜์–ด team.id๊ฐ€ ์ƒ์„ฑ๋œ ํ›„, JPA๋Š” member1๊ณผ member2์˜ ์™ธ๋ž˜ ํ‚ค๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.

์ด๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ฐ„์˜ ์—ฐ๊ด€๊ด€๊ณ„๊ฐ€ ์ผ๊ด€๋˜๊ฒŒ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค. ๐Ÿ˜Š


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

→ ์ด๋ ‡๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋Š” ์ด์œ ๋Š” @JoinedColumn(name = "TEAM_ID") ๋•Œ๋ฌธ์ธ๊ฑด๊ฐ€?

 

๋„ค ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค! JPA๊ฐ€ ์—”ํ‹ฐํ‹ฐ ๊ฐ„์˜ ์—ฐ๊ด€๊ด€๊ณ„๋ฅผ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ์ด์œ ๋Š”, @JoinColumn ์–ด๋…ธํ…Œ์ด์…˜์„ ํ†ตํ•ด **์™ธ๋ž˜ ํ‚ค(FK)**์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ปฌ๋Ÿผ ๊ฐ„์˜ ๋งคํ•‘ ์ •๋ณด๋ฅผ ๋ช…ํ™•ํžˆ ์ „๋‹ฌ๋ฐ›์•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๐Ÿ˜ JPA์™€ @JoinColumn์˜ ์—ญํ• 

@JoinColumn์˜ ์—ญํ• 

  1. ์™ธ๋ž˜ ํ‚ค์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ปฌ๋Ÿผ ๋งคํ•‘
    • @JoinColumn(name = "TEAM_ID")๋Š” Member ์—”ํ‹ฐํ‹ฐ์˜ team ํ•„๋“œ์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ TEAM_ID ์ปฌ๋Ÿผ์„ ๋งคํ•‘ํ•ฉ๋‹ˆ๋‹ค.
    • ์ด๋ฅผ ํ†ตํ•ด JPA๋Š” team ํ•„๋“œ์— ์„ค์ •๋œ Team ์—”ํ‹ฐํ‹ฐ์˜ ์‹๋ณ„์ž(id) ๊ฐ’์„ ์™ธ๋ž˜ ํ‚ค ์ปฌ๋Ÿผ์— ์ €์žฅํ•˜๊ฑฐ๋‚˜ ๊ฐฑ์‹ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. ์—ฐ๊ด€๊ด€๊ณ„ ๊ด€๋ฆฌ
    • @ManyToOne๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉ๋˜๋ฉฐ, ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ์ด ๋˜๋Š” ํ•„๋“œ(Member.team)๋ฅผ ํ†ตํ•ด ์™ธ๋ž˜ ํ‚ค๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
    • Member.team ํ•„๋“œ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜๋ฉด, JPA๋Š” ํ•ด๋‹น ๋ณ€๊ฒฝ ๋‚ด์šฉ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์™ธ๋ž˜ ํ‚ค ์ปฌ๋Ÿผ(TEAM_ID)์„ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.

JPA์˜ ๋™์ž‘ ์›๋ฆฌ

JPA๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ๊ด€๋ฆฌ๋˜๋Š” ์—”ํ‹ฐํ‹ฐ์˜ ์ƒํƒœ๋ฅผ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค. @JoinColumn ๋•๋ถ„์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋™์ž‘์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค:

1. ์‚ฝ์ž…(INSERT) ์‹œ ์™ธ๋ž˜ ํ‚ค ์„ค์ •

  • member1.setTeam(team)์œผ๋กœ team ํ•„๋“œ๋ฅผ ์„ค์ •ํ•˜๋ฉด, JPA๋Š” team.getId() ๊ฐ’์„ ์ฝ์–ด TEAM_ID๋กœ ๋งคํ•‘ํ•ฉ๋‹ˆ๋‹ค.
  • ์ด ์ •๋ณด๋ฅผ ํ†ตํ•ด Member ํ…Œ์ด๋ธ”์— ์‚ฝ์ž… ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
INSERT INTO Member (name, TEAM_ID) VALUES ('member1', 1);

2. ์—…๋ฐ์ดํŠธ(UPDATE) ์‹œ ์™ธ๋ž˜ ํ‚ค ๊ฐฑ์‹ 

  • member1.setTeam(newTeam)์œผ๋กœ team ํ•„๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉด, JPA๋Š” ์ด์ „ team.getId() ๊ฐ’๊ณผ ์ƒˆ team.getId() ๊ฐ’์„ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค.
  • ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค๋ฉด, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์™ธ๋ž˜ ํ‚ค ์ปฌ๋Ÿผ์„ ์—…๋ฐ์ดํŠธํ•˜๋Š” ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
UPDATE Member SET TEAM_ID = 2 WHERE MEMBER_ID = 1;

3. ์—ฐ๊ด€๊ด€๊ณ„ ํƒ์ƒ‰(SELECT)

  • team.getMembers()๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด JPA๋Š” TEAM_ID๋ฅผ ๊ธฐ์ค€์œผ๋กœ Member ํ…Œ์ด๋ธ”์—์„œ ๊ด€๋ จ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค.
SELECT * FROM Member WHERE TEAM_ID = 1;

@JoinColumn์ด ์—†์œผ๋ฉด?

  • @JoinColumn ์—†์ด๋„ JPA๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ํ•„๋“œ๋ช…์„ ์‚ฌ์šฉํ•ด ์™ธ๋ž˜ ํ‚ค ์ปฌ๋Ÿผ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์˜ˆ๋ฅผ ๋“ค์–ด:
    @ManyToOne
    private Team team; // @JoinColumn ์ƒ๋žต
    
  • ์ด ๊ฒฝ์šฐ JPA๋Š” ๊ธฐ๋ณธ ์ด๋ฆ„ ๊ทœ์น™์— ๋”ฐ๋ผ team_id๋ผ๋Š” ์™ธ๋ž˜ ํ‚ค ์ปฌ๋Ÿผ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
  • ํ•˜์ง€๋งŒ ๊ธฐ๋ณธ ์ด๋ฆ„๊ณผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ปฌ๋Ÿผ ์ด๋ฆ„์ด ์ผ์น˜ํ•˜์ง€ ์•Š์œผ๋ฉด, ์™ธ๋ž˜ ํ‚ค ๋งคํ•‘์ด ์‹คํŒจํ•˜๊ฑฐ๋‚˜ ์ž˜๋ชป๋œ ์ฟผ๋ฆฌ๊ฐ€ ์ƒ์„ฑ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๋ก 

JPA๊ฐ€ ์—”ํ‹ฐํ‹ฐ ๊ฐ„์˜ ์—ฐ๊ด€๊ด€๊ณ„๋ฅผ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ์ด์œ ๋Š”:

  • @JoinColumn์„ ํ†ตํ•ด ์™ธ๋ž˜ ํ‚ค ๋งคํ•‘ ์ •๋ณด๊ฐ€ ์ œ๊ณต๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.
  • JPA๋Š” ์ด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์™ธ๋ž˜ ํ‚ค ๊ฐ’์„ ์ƒ์„ฑ, ์—…๋ฐ์ดํŠธ, ์กฐํšŒํ•˜๋Š” SQL์„ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜๊ณ  ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

@JoinColumn์€ JPA์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ฐ„์˜ ์›ํ™œํ•œ ์—ฐ๋™์„ ์œ„ํ•œ ํ•ต์‹ฌ์ ์ธ ๊ตฌ์„ฑ ์š”์†Œ์ž…๋‹ˆ๋‹ค. ๐Ÿ˜Š

 

 


๐Ÿ“š ์ถœ์ฒ˜ : ChatGPT

๋Œ“๊ธ€