Backend/JPA

[JPA] ๊ฐ์ฒด ์ง€ํ–ฅ ๋ชจ๋ธ๋ง๊ณผ ์–‘๋ฐฉํ–ฅ,๋‹จ๋ฐฉํ–ฅ ์—ฐ๊ด€๊ด€๊ณ„ ๋งคํ•‘

์žฅ์šฉ์„ 2024. 2. 17. 14:23

๐Ÿค” ๊ธฐ์กด์˜ ๋ฌธ์ œ์ 

๊ฐ์ฒด๋ฅผ ํ…Œ์ด๋ธ”์— ๋งž์ถ”์–ด ๋ชจ๋ธ๋ง

try{
  //ํŒ€ ๋“ฑ๋ก
  Team team = new Team();
  team.setName("TeamA");
  em.persist(team);
  //๋งด๋ฒ„ ๋“ฑ๋ก
  Member member = new Member();
  member.setUsername("member1");
  member.setTeamId(team.getId()); // **์™ธ๋ž˜ํ‚ค ์‹๋ณ„์ž๋ฅผ ์ง์ ‘ ๋‹ค๋ฃจ๊ณ  ์žˆ๋‹ค.**
  em.persist(member);
  //์กฐํšŒ
  Member findMember = em.find(Member.class, member.getId());

  Long findTeamId = findMember.getTeamId(); // ๋งด๋ฒ„๊ฐ์ฒด์— ์ €์žฅ๋œ ํŒ€์•„์ด๋”” ์ฆ‰ ์™ธ๋ž˜ํ‚ค๋ฅผ ์ฐพ๋Š”๋‹ค
  Team findTeam = em.find(Team.class, findTeamId); //์ฐพ์€ ์™ธ๋ž˜ํ‚ค๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋‹ค์‹œ ์กฐํšŒ

  tx.commit();
}

์œ„์˜ ์ฝ”๋“œ์ฒ˜๋Ÿผ ๊ฐ์ฒด๋ฅผ ํ…Œ์ด๋ธ”์— ๋งž์ถ”์–ด์„œ ๋ชจ๋ธ๋งํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ์ฒด๋ฅผ ๋‹ค๋ฃจ๋Š”๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๊ด€๊ณ„ํ˜•๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ๊ฐ์ฒด๋ฅผ ๋‹ค๋ฃจ๊ณ  ์žˆ์„ ๋ฟ ์•„๋‹ˆ๋ผ ์ ˆ์ฐจ๊ฐ€ ๋ณต์žกํ•˜๊ฒŒ ๋А๊ปด์ง„๋‹ค.

  • ํ…Œ์ด๋ธ”์€ ์™ธ๋ž˜ ํ‚ค๋กœ ์กฐ์ธ์„ ์‚ฌ์šฉํ•ด์„œ ์—ฐ๊ด€๋œ ํ…Œ์ด๋ธ”์„ ์ฐพ๋Š”๋‹ค
  • ๊ฐ์ฒด๋Š” ์ฐธ์กฐ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์—ฐ๊ด€๋œ ๊ฐ์ฒด๋ฅผ ์ฐพ๋Š”๋‹ค.

 


โœ” ๊ฐ์ฒด ์ง€ํ–ฅ ๋ชจ๋ธ๋ง

๐Ÿ”Ž ๋‹จ๋ฐฉํ–ฅ ๋งคํ•‘

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

    @Column(name = "username")
    private String name;

    @ManyToOne
    @JoinColumn(name = "TEAM_ID")
    private Team team;

    ...
 }

Memberํด๋ž˜์Šค ์ž…์žฅ์—์„œ Team๊ณผ N : 1 ๊ด€๊ณ„์ด๊ธฐ ๋•Œ๋ฌธ์— @ManyToOne ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ์ฒด์˜ ์ฐธ์กฐ๊ด€๊ณ„์™€ ํ…Œ์ด๋ธ”์˜ ์™ธ๋ž˜ ํ‚ค๋ฅผ ๋งคํ•‘ํ•œ๋‹ค.

try{
  //ํŒ€ ๋“ฑ๋ก
  Team team = new Team();
  team.setName("TeamA");
  em.persist(team);
  //๋งด๋ฒ„ ๋“ฑ๋ก
  Member member = new Member();
  member.setUsername("member1");
  member.setTeam(team); // ํŒ€์˜ ์•„์ด๋””๊ฐ€ ์•„๋‹Œ ํŒ€ ๊ฐ์ฒด๋ฅผ ๊ทธ๋Œ€๋กœ ์„ธํŒ…
  em.persist(member);
  //์กฐํšŒ
  Member findMember = em.find(Member.class, member.getId());

  findMember.getTeam(); // ๋ฐ”๋กœ findMember์™€ ์—ฐ๊ด€๋œ ํŒ€๊ฐ์ฒด๋ฅผ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค.

  tx.commit();
}
...

๊ฐ์ฒด์ง€ํ–ฅ ์Šค๋Ÿฝ๊ฒŒ ๋ฐ”๋กœ ์—ฐ๊ด€๋œ ๋ ˆํผ๋Ÿฐ์Šค๋“ค์„ ๊ฐ€์ง€๊ณ ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

 

๐Ÿ”Ž ์–‘๋ฐฉํ–ฅ ๋งคํ•‘

๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ๋Š” ์™ธ๋ž˜ ํ‚ค ํ•˜๋‚˜๋กœ ์–‘์ชฝ ํ…Œ์ด๋ธ”์„ ์กฐ์ธํ•ด์„œ Member์™€ Team์˜ ์ •๋ณด๋ฅผ ์กฐํšŒํ•  ์ˆ˜ ์žˆ์—ˆ์ง€๋งŒ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•ด์„œ๋Š” ๋ถˆ๊ฐ€๋Šฅํ–ˆ๋‹ค.
์–‘๋ฐฉํ–ฅ ์กฐํšŒ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋„๋ก ๊ด€๊ณ„๊ฐ€ ๋˜๋Š” ๋‘ ๊ฐ์ฒด(Entity)์‚ฌ์ด์— ๋ชจ๋‘ ์—ฐ๊ด€๊ด€๊ณ„๋ฅผ ์„ค์ •ํ•ด ์คŒ์œผ๋กœ์จ ์–‘๋ฐฉํ–ฅ ์กฐํšŒ,์ˆ˜์ •์ด ๊ฐ€๋Šฅํ•ด์ง„๋‹ค.


๐Ÿ’ก ์—ฐ๊ด€๊ด€๊ณ„ ์ฃผ์ธ? mappedBy?
์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„์—์„œ ์˜ˆ๋ฅผ๋“ค์–ด ์ˆ˜์ •์„ ํ•ด์•ผํ•œ๋‹ค๋ฉด Memberํด๋ž˜์Šค์˜ team์„ ์ˆ˜์ • ํ•ด์•ผํ• ๊นŒ์š”? Team์˜ members ๋ฆฌ์ŠคํŠธ๋ฅผ ์ˆ˜์ •ํ•ด์•ผ ํ• ๊นŒ์š”? ๋ผ๋Š” ์˜๋ฌธ์ด ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‹ค.
์ฆ‰ ์™ธ๋ž˜ ํ‚ค๋ฅผ ์–ด๋””์„œ ๊ด€๋ฆฌํ• ์ง€์˜ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๊ฒŒ ๋˜๋Š”๋ฐ ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ์œ„ํ•ด ์™ธ๋ž˜ํ‚ค๋ฅผ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๋Š” ๊ฐ์ฒด์— mappedBy์„ ์‚ฌ์šฉํ•ด์„œ ๋‹ค๋ฅธ ๊ฐ์ฒด ์ฆ‰ ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ์œผ๋กœ๋ถ€ํ„ฐ ๋งคํ•‘ ๋˜์–ด์ ”๋‹ค ๋ผ๊ณ  ์„ค์ •ํ•˜์—ฌ ์ฃผ์ธ ๊ฐ์ฒด๋งŒ์ด ๋“ฑ๋ก, ์ˆ˜์ •์ด ๊ฐ€๋Šฅํ•˜๊ณ  ๋งคํ•‘๋˜์–ด์ง„ ๊ฐ์ฒด๋Š” ์ฝ๊ธฐ๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค.

  • ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ๋งŒ์ด ์™ธ๋ž˜ ํ‚ค๋ฅผ ๊ด€๋ฆฌ(๋“ฑ๋ก, ์ˆ˜์ •)
  • ์ฃผ์ธ์ด ์•„๋‹Œ์ชฝ์€ ์ฝ๊ธฐ๋งŒ ๊ฐ€๋Šฅ
  • ์ฃผ์ธ์€ mappedBy ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ , ์•„๋‹Œ์ชฝ์€ mappedBy ์†์„ฑ์œผ๋กœ ์ฃผ์ธ์„ ์ง€์ •ํ•ด์ค€๋‹ค.

 

๐Ÿ’ก ๋ˆ„๊ตฌ๋ฅผ ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ์œผ๋กœ?
์™ธ๋ž˜ ํ‚ค๊ฐ€ ์žˆ๋Š” ๊ณณ์„ ์ฃผ์ธ์œผ๋กœ ์ง€์ •ํ•œ๋‹ค.

DB๊ด€์ ์—์„œ ๋ณด๋ฉด FK๊ฐ€ ์žˆ๋Š”๊ณณ์ด N์ด๊ณ  PK์ชฝ์ด 1์ด๋‹ค (N : 1)
FK๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํ…Œ์ด๋ธ”(Member)๊ณผ ๋Œ€์‘๋˜๋Š” ๊ฐ์ฒด(Member)๋ฅผ ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ์œผ๋กœ ์„ค์ •ํ•ด์•ผ updateํ–ˆ์„๋•Œ ์ง๊ด€์ ์œผ๋กœ ์•Œ๊ธฐ ์‰ฝ๋‹ค.

 

๐Ÿ’ก ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ์ชฝ์—๋งŒ ๊ฐ’์„ ์„ธํŒ…ํ•ด์ฃผ๋ฉด ๋ ๊นŒ?

try {
            //ํŒ€ ๋“ฑ๋ก
            Team team = new Team();
            team.setName("TeamA");
            em.persist(team);
            //๋งด๋ฒ„ ๋“ฑ๋ก
            Member member = new Member();
            member.setUsername("member1");
            member.setTeam(team);
            em.persist(member);

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

            Member findMember = em.find(Member.class, member.getId());
            List<Member> members = findMember.getTeam().getMembers();

            for ( Member mbr : members){
                System.out.println("mbr = " + mbr.getUsername());
            }

            tx.commit();
      }

์œ„ ์ฝ”๋“œ์—์„œ๋Š” ์ •์ƒ์ ์œผ๋กœ member๋ฆฌ์ŠคํŠธ๋ฅผ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค ๊ทธ ์ด์œ ๋Š” flush๋ฅผ ํ†ตํ•ด sql๋ฌธ์„ commit์ด์ „์— ๊ฐ•์ œ๋กœ ์š”์ฒญํ•œ ํ›„ clear๋ฅผ ์‚ฌ์šฉํ•ด์„œ 1์ฐจ์บ์‹œ๋ฅผ ๋น„์›Œ์คŒ์œผ๋กœ์จ ๋‹ค์Œ์˜ ์ฝ”๋“œ์ธ em.find๋ฅผ ํ†ตํ•ด ์กฐํšŒ๋  ๋•Œ 1์ฐจ์บ์‹œ์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๊ธฐ๋•Œ๋ฌธ์— DB์— select๋ฌธ์„ ์š”์ฒญํ•˜๊ฒŒ๋˜๊ณ , ์—ฐ๊ด€๊ด€๊ณ„ ๋งคํ•‘์— ์˜ํ•ด์„œ ์—ฐ๊ด€๋œ ํ…Œ์ด๋ธ”์„ joinํ•˜์—ฌ member๋ฆฌ์ŠคํŠธ๋„ selectํ•˜์—ฌ 1์ฐจ์บ์‹œ์— ์ €์žฅํ•˜๊ฒŒ ๋œ๋‹ค.

 

์ด๋•Œ๋ฌธ์— member๋ฆฌ์ŠคํŠธ๊ฐ€ ์กฐํšŒ๋  ์ˆ˜ ์žˆ์—ˆ๋‹ค.
ํ•˜์ง€๋งŒ flush์™€ clear๋ฅผ ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์—ฐ๊ด€๊ด€๊ณ„๊ฐ€ ์„ค์ •๋˜๊ธฐ ์ด์ „์˜ ํŒ€๊ณผ ๋งด๋ฒ„ ๊ฐ์ฒด๊ฐ€ 1์ฐจ ์บ์‹œ์— ๊ทธ๋Œ€๋กœ ๋‚จ์•„์žˆ๊ธฐ ๋•Œ๋ฌธ์— member๋ฆฌ์ŠคํŠธ๋Š” ์•„๋ฌด๋Ÿฐ ๊ฐ’๋„ ๊ฐ€์ง€๊ณ  ์žˆ์ง€ ์•Š๊ฒŒ๋œ๋‹ค.
์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ์œ„ํ•ด ์–‘๋ฐฉํ–ฅ ์—ฐ๊ด€๊ด€๊ณ„๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ์—๋Š” ์–‘์ชฝ์— ๋‹ค ๊ฐ’์„ ์„ธํŒ…ํ•ด์ฃผ๋Š”๊ฒƒ์ด ๋งž๋‹ค.

try {
            //ํŒ€ ๋“ฑ๋ก
            Team team = new Team();
            team.setName("TeamA");
            em.persist(team);
            //๋งด๋ฒ„ ๋“ฑ๋ก
            Member member = new Member();
            member.setUsername("member1");
            member.setTeam(team); // ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ์ชฝ์— ๊ฐ’ ์„ธํŒ… 1
            em.persist(member);

            team.getMembers().add(member); // ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ์ด ์•„๋‹Œ์ชฝ์— ๊ฐ’ ์„ธํŒ… 2

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

            Member findMember = em.find(Member.class, member.getId());
            List<Member> members = findMember.getTeam().getMembers();

            for ( Member mbr : members){
                System.out.println("mbr = " + mbr.getUsername());
            }

            tx.commit();
      }

์ˆœ์ˆ˜ ๊ฐ์ฒด ์ƒํƒœ๋ฅผ ๊ณ ๋ คํ•ด์„œ ํ•ญ์ƒ ์–‘์ชฝ์— ๊ฐ’์„ ์„ค์ • ํ•ด์•ผํ•œ๋‹ค.
๊ฐ’์„ 2๋ฒˆ ์„ค์ •ํ•˜๊ธฐ๋•Œ๋ฌธ์— ์‹ค์ˆ˜์— ์—ฌ์ง€๊ฐ€ ์žˆ๋‹ค ์ด๋Ÿฌํ•œ ์‹ค์ˆ˜๋ฅผ ์ค„์ด๊ณ ์ž ํŽธ์˜ ๋ฉ”์†Œ๋“œ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

// Memeber
public void changeTeam(Team team){
    this.team = team; //team์„ ์„ค์ •ํ•ด์ฃผ๋Š” ์‹œ์ ์—
    team.getMembers.add(this); //๋ฐ”๋กœ this(Member)๋ฅผ member๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€
}

๐Ÿ“Œ

  • toString(), lombok, JSON์ƒ์„ฑ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋“ฑ ๋ฌดํ•œ๋ฃจํ”„๋ฅผ ์กฐ์‹ฌํ•˜์ž!
  • ๋‹จ๋ฐฉํ–ฅ ๋งคํ•‘๋งŒ์œผ๋กœ๋„ ์ด๋ฏธ ์—ฐ๊ด€๊ด€๊ณ„ ๋งคํ•‘ ์™„๋ฃŒ๋œ ์ƒํƒœ์ด๋‹ค.
  • ์–‘๋ฐฉํ–ฅ ๋งคํ•‘์€ ๋ฐ˜๋Œ€ ๋ฐฉํ–ฅ์œผ๋กœ ์กฐํšŒ(๊ฐ์ฒด ๊ทธ๋ž˜ํ”„ ํƒ์ƒ‰) ๊ธฐ๋Šฅ์ด ์ถ”๊ฐ€๋œ ๊ฒƒ ๋ฟ์ด๋‹ค.
  • ์‹ค๋ฌด์—์„œ๋Š” JPQL์—์„œ ์—ญ๋ฐฉํ–ฅ์œผ๋กœ ํƒ์ƒ‰ํ•  ์ผ์ด ๋งŽ๋‹ค.
  • ๋‹จ๋ฐฉํ–ฅ ๋งคํ•‘์„ ์ž˜ ํ•˜๊ณ  ์–‘๋ฑกํ•ญ์€ ํ•„์š”ํ•  ๋•Œ ์ถ”๊ฐ€ํ•ด๋„ ๋œ๋‹ค.(ํ…Œ์ด๋ธ”์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Œ)

๐Ÿ“š ์ฐธ๊ณ  ๋ฐ ์ž๋ฃŒ ์ถœ์ฒ˜ : ์ž๋ฐ” ORM ํ‘œ์ค€ JPA ํ”„๋กœ๊ทธ๋ž˜๋ฐ - ๊ธฐ๋ณธํŽธ (๊น€์˜ํ•œ)