티스토리 뷰
참고로 이 기능은 순수 JPA 2.2 부터 들어간 기능이라 한다.
@Test
public void findMemberLazy(){
Team teamA = new Team("teamA");
Team teamB = new Team("teamB");
teamRepository.save(teamA);
teamRepository.save(teamB);
Member member1 = new Member("member1", 10, teamA);
Member member2 = new Member("member2", 10, teamB);
memberRepository.save(member1);
memberRepository.save(member2);
em.flush();
em.clear();
List<Member> members = memberRepository.findAll();
for (Member member : members) {
System.out.println("member.getUsername = " + member.getUsername());
System.out.println("member.getTeam = " + member.getTeam());
System.out.println("member.getTeam().getName" + member.getTeam().getName());
}
}
package study.datajpa.entity;
import jakarta.persistence.*;
import lombok.*;
@Entity
@Getter @Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED) // 기본생성자 만들기, 기본생성자는 JPA 스펙으로 private는 안된다.
@ToString(of = {"id", "username", "age"}) //toString을 만들 때에는 가급적이면 연관관계객체는 넣지 않는것이 좋다(서로 부르면서 무한루프 된다.)
@NamedQuery(
name="Member.findByUsername",
query="select m from Member m where m.username =: username"
)
public class Member {
@Id @GeneratedValue
@Column(name = "member_id")
private Long id;
private String username;
private int age;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "team_id")
private Team team;
public Member(String username) { this.username = username; }
public Member(String username, int age) {
this.username = username;
this.age = age;
}
public Member(String username, int age, Team team) {
this.username = username;
this.age = age;
if(team != null) {
changeTeam(team);
}
}
public void changeTeam(Team team){
this.team = team;
team.getMembers().add(this);
}
}
위의 코드에서 Member 객체 안에 Team은 현재 FetchType.LAZY로 설정 되어있다. member에 대한 findAll을 했을 때에는 team에 대한 쿼리가 날아가지 않는다.
후에 team을 호출하는 for문이 돌아 갈때 한개씩 조인하여 가져온다.
이 문제는 1 + N의 문제를 유발하는데 데이터가 많아질 경우 트래픽을 유발 할 수 있다는 문제점이 있다.
문제점을 바로 잡기 위해 보통은 쿼리에 join fetch를 넣어 해결한다.
@Query("select m from Member m join fetch m.team")
List<Member> findMemberFetchJoin();
data JPA에서는 위와 같은 방법을 사용할 수도 있지만 좀더 편리한 방법이 있다. 매번 join fetch를 넣어 해결하는 방식은 시간을 잡을 수 있어서 인지 줄여버렸다.
@EntityGraph를 사용하는 방식이다.
@Override
@EntityGraph(attributePaths = {"team"})
List<Member> findAll();
이렇게 객체 그래프를 엮어서 가져올 수가 있다
@EntityGraph(attributePaths = {"team"})
@Query("select m from Member m")
List<Member> findMemberEntityGraph();
이런 식으로 함께 사용할 수도 있다.
@EntityGraph(attributePaths = {"team"})
List<Member> findEntityGraphByUsername(@Param("username") String username);
순수 JPA에서 사용하는 방법도 소개한다.
...
@NamedEntityGraph(name = "Member.All" , attributeNodes = @NamedAttributeNode("team"))
public class Member {
@Id @GeneratedValue
@Column(name = "member_id")
private Long id;
private String username;
private int age;
....
@EntityGraph("Member.All")
List<Member> findEntityGraph2ByUsername(@Param("username") String username);
이렇게도 작동한다.
'dev_공부일지 > spring data JPA' 카테고리의 다른 글
확장 기능 - 사용자 정의 레퍼지토리 (0) | 2024.03.06 |
---|---|
JPA Hint & Lock (0) | 2024.03.06 |
벌크성 수정 쿼리 (0) | 2024.03.05 |
변환 타입 (중요, null체크) , 페이징과 정렬 (0) | 2024.03.05 |
@Query 값 DTO 조회하기 , 파라미터 바인딩 (0) | 2024.03.05 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- BindingResult
- hypertexttransferprotocol
- 향해99
- 항해99
- JPA
- 예외처리
- jpa api
- reject
- Java
- react실행
- 백엔드 개발자 역량
- React
- exception
- SpringBoot
- Intercepter
- 백엔드 개발자 공부
- 항해플러스
- rejectValue
- 컨트
- 스프링부트
- 스프링공부
- 인터셉터
- 로그인
- 향해플러스백엔드
- thymleaf
- 향해플러스
- 리터럴
- filter
- HTTP
- ArgumentResolver
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
글 보관함