Notice
Recent Posts
Link
Tags
- SSL
- spring mvc
- 데이터베이스
- 스프링
- mysql
- DI
- 프로그래머스
- Docker
- Django
- 1차원 배열
- sql
- spring boot
- ORM
- spring security 6
- session
- join
- Git
- @transactional
- 문자열
- string
- 자바
- nginx
- java
- select
- spring
- AWS
- 스프링부트
- jpa
- PYTHON
- springboot
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Archives
개발하는 자몽
[JPA] 지연로딩과 프록시 객체 조회 본문
findById() 메서드로 L엔티티를 조회하고 가져온 엔티티의 getter 메서드에 접근했더니 아래와 같은 에러가 발생했다.
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role
위 에러는 엔티티는 잘 가져왔지만, 이후 해당 엔티티를 통해 어떤 메소드를 호출하려고 할 때 이미 영속성 컨텍스트가 닫혀서 지연로딩을 할 수 없을 때 발생한다.
상황
application.yml
...
spring.jpa.open-in-view=false
...
spring.jpa.open-in-view 옵션에 관하여는 이 글을 참고하자 ( https://velog.io/@dnwlsrla40/JPA-Open-In-View )
Team 클래스
...
@Getter
@Entity
public class Team {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(mappedBy = "members")
private List<Member> members;
...
}
Member 클래스
...
@Entity
@Getter
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToOne
private Team team;
...
}
TeamController 클래스
...
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("teams")
public class TeamControlelr {
private final TeamRepository teamRepository;
@GetMapping("{id}/members")
public void readTeamMembers(@PathVariable("id") Long id) {
Team team = teamRepository.findById(id)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
for (Member membmer : team.getMember()) {
log.info("team: {} - membmer: {}", team.getName(), membmer.getName()); //에러 발생
}
}
...
}
Team 엔티티를 가져오고 Team 엔티티와 연관관계가 매핑된 Member를 getMembers()로 조회할 때 에러가 발생한다.
원인 분석
...
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("teams")
public class TeamControlelr {
private final TeamRepository teamRepository;
@GetMapping("{id}/members")
public void readTeamMembers(@PathVariable("id") Long id) {
1. findById로 Team 조회 : repository에서 조회했을 땐 영속 상태(지연 로딩이므로 proxy 객체), open-in-view=false 이므로 controller에서 영속성 컨텍스트는 닫힌 상태(즉, 준영속 상태)
2. 조회한 Team (proxy) 객체의 getMembers() 요청
2-1. 요청 시 proxy 객체의 타겟은 null 이므로 getXxx() 메소드 없음, 존재하는 건 실제 객체의 참조.
2-2. 영속성 컨텍스트에 실제 Entity로 초기화를 요청
2-3. 영속성 컨텍스트가 DB에서 실제 객체를 찾는다
2-4. proxy 객체와 실제 객체 연결
2-5. 이제 proxy 객체는 getMembers()를 실제 객체의 getMembers()로 처리 가능
3. 그런데 여기서 proxy 객체는 준영속 상태이므로 초기화 요청 시 오류가 난다(즉, 2-2 에서 에러)
4. 해당 에러 발생!
}
...
}
해결
영속성 컨텍스트를 유지하기 위해 해당 메서드에 @Transactional을 적용시키거나 spring.jpa.open-in-view 옵션을 true로 설정하면 된다.
SUMMARY
지연 로딩일 때 'spring.jpa.open-in-view=false'면 해당 에러가 발생
'Java > Spring' 카테고리의 다른 글
[Spring Data JPA] TransactionRequiredException (0) | 2023.08.19 |
---|---|
[QueryDSL] SpringBoot 3.1.0, QueryDSL 5.0.0 build.gradle (0) | 2023.08.12 |
[JPA] 더티체킹과 update (0) | 2023.06.26 |
[Spring] 패키지 구조 설계 (0) | 2023.06.19 |
[JPA] OneToMany 양방향 관계 (0) | 2023.06.14 |
Comments