[JPA] proxy, fetch ์ „๋žต

1. ๋“ค์–ด๊ฐ€๋ฉฐ

ํ”„๋ก์‹œ์˜ ๊ธฐ๋ณธ๊ณผ, JPA์—์„œ fetch ์ „๋žต์ด ์–ด๋–ค ๊ฒƒ๋“ค์ด ์žˆ๋Š” ์ง€ ์•Œ์•„๋ณด์ž.

ํ”„๋ก์‹œ ๊ธฐ์ดˆ

PA์—์„œ ์‹๋ณ„์ž๋กœ ์—”ํ‹ฐํ‹ฐ ํ•˜๋‚˜๋ฅผ ์กฐํšŒํ•  ๋•Œ EntityManager.find()๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ์ด ๋ฉ”์„œ๋“œ๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์—†์œผ๋ฉด ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค๋ฅผ ์กฐํšŒํ•œ๋‹ค.

Member member = em.find(Member.class, "member1");

๋งŒ์•ฝ์— ์—”ํ‹ฐํ‹ฐ๋ฅผ ์‹ค์ œ ์‚ฌ์šฉํ•˜๋Š” ์‹œ์ ๊นŒ์ง€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์กฐํšŒ๋ฅผ ๋ฏธ๋ฃจ๊ณ  ์‹ถ์œผ๋ฉด EntityManger.getReference()๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

Member member = em.getReference(Member.class, "member1");

์ด ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ JPA๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์กฐํšŒํ•˜์ง€ ์•Š๊ณ  ์‹ค์ œ ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋„ ์ƒ์„ฑํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋Œ€์‹ ์— ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ ‘๊ทผ์„ ์œ„์ž„ํ•œ ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

์ฆ‰์‹œ๋กœ๋”ฉ ์‹œ, JPA๋Š” ์™ธ๋ถ€์กฐ์ธ(Left Outer) ์กฐ์ธ์„ ์‚ฌ์šฉํ•œ๋‹ค. ๊ทธ ์ด์œ ๋Š” ๋‚ด๋ถ€์กฐ์ธ์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด, ์™ธ๋ž˜ํ‚ค null๊ฐ’์ด ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ, ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ์–ด๋–ค ๋ฐ์ดํ„ฐ๋„ ์กฐํšŒํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์„ฑ๋Šฅ์ ์ธ ์ธก๋ฉด์—์„œ ๋‚ด๋ถ€ ์กฐ์ธ์ด ์ข‹๊ธฐ ๋•Œ๋ฌธ์—. ๋‚ด๋ถ€์กฐ์ธ์„ ์‚ฌ์šฉํ• ๋ ค๋ฉด, ์™ธ๋ž˜ํ‚ค๋ฅผ not null ์กฐ๊ฑด์œผ๋กœ ํŠน์ •ํ•ด์•ผ ํ•œ๋‹ค

@Entity
public class Member {
  //...
  @ManyToOne(fetch = FetchType.EAGER)
  @JoinColumn(name="TEAM_ID", nullable = false)
  private Team team;
  //...
}

2. ์˜ˆ์ œ์ฝ”๋“œ

์œ„์˜ ๋ง์ด ์ •ํ™•ํžˆ ์ดํ•ด๊ฐ€ ๊ฐ€์ง€ ์•Š์•„์„œ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ์ž‘์„ฑํ•ด ๋ณด์ž.
๊ฐ„๋‹จํ•œ Team(1): Member(N) ๊ด€๊ณ„๋ฅผ ๊ฐ–๊ณ  (์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„) ๋งคํ•‘์„ ํ•ด๋ณด์ž.

@Data
@Entity
@Table(name = "TEAM")
public class Team {

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

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

    @OneToMany
    private List<Member> memberList = new ArrayList<>();
}
@Data
@Entity
@Table(name = "MEMBER")
public class Member {

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

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

    @Column(name = "AGE")
    private Integer age;

    @ManyToOne
    @JoinColumn(name = "TEAM_ID")
    private Team team;
}
    @Test
    public void teamTest() {

        //Given
        Member member = new Member();
        member.setName("andrew");
        member.setAge(32);

        Team team = new Team();
        team.setName("AํŒ€");

        //์—ฐ๊ด€๊ด€๊ณ„ ์„ค์ •
        member.setTeam(team);
        team.getMemberList().add(member);

        teamRepository.save(team);
        memberRepository.save(member);

        //When
        Member existMember = memberRepository.findById(member.getId()).get();

        //Then
        Assert.assertEquals(existMember.getTeam().getName(), "AํŒ€");

    }

์ด ํ…Œ์ŠคํŠธ๋Š” Member, Team ๊ฐ์ฒด๋ฅผ ์ €์žฅ ํ•˜๊ณ , ๊ฐ์ฒด ๊ทธ๋ž˜ํ”„ ํƒ์ƒ‰ํ•˜๋Š” ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค ์ž…๋‹ˆ๋‹ค.

์œ„์—์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด, ์ฆ‰์‹œ ๋กœ๋”ฉํ•œ ๊ฒฝ์šฐ, left outer join ์„ ํ•œ๋‹ค.

select
        member0_.member_id as member_i1_1_0_,
        member0_.age as age2_1_0_,
        member0_.name as name3_1_0_,
        member0_.team_id as team_id4_1_0_,
        team1_.team_id as team_id1_2_1_,
        team1_.name as name2_2_1_
    from
        member member0_
    left outer join
        team team1_
            on member0_.team_id=team1_.team_id
    where
        member0_.member_id=?

JPA ์—์„œ ๊ธฐ๋ณธ Fetch ์ „๋žต

์ฆ‰์‹œ ๋กœ๋”ฉ์ธ์ง€ ์•„๋‹Œ์ง€ ์•Œ์•„ ๋ณด๊ธฐ ์œ„ํ•ด์„œ fetch ์˜ต์…˜์„ ์‚ดํŽด๋ณด์ž. JPA์—์„œ๋Š” ๊ธฐ๋ณธ fetch ์ „๋žต์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

์—ฐ๊ด€ ๊ด€๊ณ„๊ฐ€ 1:N ์œผ๋กœ ๋งคํ•‘์ด ๋˜๋ฉด, ๋‹น์—ฐํžˆ ์ฆ‰์‹œ ๋กœ๋”ฉํ•˜๊ฒŒ ๋˜๋ฉด, ๋งค๋ฒˆ ์กฐ์ธ ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์„ฑ๋Šฅ์— ์•ˆ ์ข‹์€ ์˜ํ–ฅ์„ ๋ฏธ์นœ๋‹ค. ๊ทธ์™€๋Š” ๋ฐ˜๋Œ€๋กœ N:1 ์€ ์ฆ‰์‹œ ๋กœ๋”ฉ์ด ๊ธฐ๋ณธ ์ „๋žต์ด๋‹ค.

์œ„์˜ ์˜ˆ์ œ์—์„œ๋Š” Member(N): Team(1) ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ฆ‰์‹œ ๋กœ๋”ฉ์ด ๋œ๋‹ค.

์ด๋ฒˆ์—๋Š” lazy ๋กœ๋”ฉ์œผ๋กœ ํ…Œ์ŠคํŠธ ํ•ด๋ณด์ž

    @Test
    public void lazy๋กœ๋”ฉ_teamTest() {

        //Given
        Member member = new Member();
        member.setName("andrew");
        member.setAge(32);

        Team team = new Team();
        team.setName("AํŒ€");

        //์—ฐ๊ด€๊ด€๊ณ„ ์„ค์ •
        member.setTeam(team);
        team.getMemberList().add(member);

        teamRepository.save(team);
        memberRepository.save(member);

        //When
        Team existTeam = teamRepository.findById(team.getId()).get();

        //Then
        Assert.assertEquals(existTeam.getMemberList().get(0).getName(), "andrew");

    }

๋‹ค์Œ๊ณผ ๊ฐ™์€ Exception์ด ๋ฐœ์ƒํ•œ๋‹ค.

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.example.demo.spring.jpa.team.Team.memberList, could not initialize proxy - no Session

ํ•ด๊ฒฐ๋ฐฉ๋ฒ•์€

๋‘ ๊ฐœ๊ฐ€ ๊ฐ™์€ ์ฟผ๋ฆฌ๋ฅผ ๋งŒ๋“œ๋‚˜..?

TODO

์—ฐ๊ด€ ํฌ์ŠคํŠธ