초기화 문제는 Lazy Loading 방식에서 프록시 객체(proxy object)가 초기화되지 못하는 상황에서 발생합니다. 이 문제는 LazyInitializationException이라는 예외로 나타나며, 일반적으로 Hibernate/JPA 환경에서 자주 겪게 됩니다.
Session/EntityManager 종료 후 데이터 접근
잘못된 트랜잭션 관리
User
엔터티는 orders
라는 연관 데이터를 Lazy Loading으로 설정.orders
에 접근.@Entity
public class User {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
private List<Order> orders;
}
@Entity
public class Order {
@Id
@GeneratedValue
private Long id;
private String product;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
}
@Service
public class UserService {
public User getUserById(Long id) {
return userRepository.findById(id).orElseThrow();
}
}
@RestController
public class UserController {
@GetMapping("/users/{id}")
public String getUserOrders(@PathVariable Long id) {
User user = userService.getUserById(id);
// LazyInitializationException 발생: orders 초기화 불가
return "Orders: " + user.getOrders().size();
}
}
userService.getUserById(id)
에서 User
를 반환할 때 orders
는 아직 초기화되지 않은 상태입니다.Session
이 이미 닫힌 상태에서 컨트롤러가 orders
에 접근하려고 시도하면 예외가 발생합니다.Fetch Join 사용
@Query("SELECT u FROM User u JOIN FETCH u.orders WHERE u.id = :id")
Optional<User> findByIdWithOrders(@Param("id") Long id);
Open Session In View(OSIV) 패턴 사용
application.properties
에서 설정.spring.jpa.open-in-view=false
DTO(Data Transfer Object) 활용
public class UserDTO {
private String name;
private List<String> orders;
public UserDTO(User user) {
this.name = user.getName();
this.orders = user.getOrders().stream()
.map(Order::getProduct)
.collect(Collectors.toList());
}
}
Hibernate Batch Fetching
@Entity
@BatchSize(size = 10)
public class User {
// 필드
}
Transaction 범위 확장
@Transactional
을 사용하여 범위를 확장.@Transactional
public User getUserWithOrders(Long id) {
User user = userRepository.findById(id).orElseThrow();
user.getOrders().size(); // Lazy Loading 강제 초기화
return user;
}
추가 학습 자료