본문 바로가기

Spring Boot

[Spring Boot] Spring JPA Entity 연관관계 및 즉시로딩, 지연로딩

728x90

Spring JPA Entity 연관관계 및 즉시로딩, 지연로딩

개요

Spring Data JPA는 엔티티 간의 연관관계를 설정하고 관리하는 강력한 기능을 제공합니다. 엔티티 간의 연관관계는 데이터베이스의 테이블 간의 관계와 유사합니다. JPA에서는 엔티티 간의 관계를 맵핑하고, 데이터 로딩 방식을 제어할 수 있는 다양한 옵션을 제공합니다. 이 글에서는 JPA의 엔티티 연관관계와 즉시로딩(Eager Loading), 지연로딩(Lazy Loading)에 대해 자세히 설명하겠습니다.

목차

  1. 엔티티 연관관계 개념
  2. 연관관계 유형
  3. 연관관계 매핑 예제
  4. 즉시로딩과 지연로딩
  5. 로딩 전략 선택 시 고려사항
  6. 예제 코드
  7. 요약

 

1. 엔티티 연관관계 개념

 

엔티티 연관관계는 데이터베이스 테이블 간의 관계를 엔티티 객체 간의 관계로 매핑한 것입니다. 이를 통해 객체 지향적으로 데이터를 처리할 수 있습니다.

 

2. 연관관계 유형

JPA에서는 다음과 같은 엔티티 간의 연관관계를 지원합니다:

  • 일대일(One-to-One) 관계
  • 일대다(One-to-Many) 관계
  • 다대일(Many-to-One) 관계
  • 다대다(Many-to-Many) 관계

 

3. 연관관계 매핑 예제

일대일(One-to-One) 관계

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @OneToOne
    @JoinColumn(name = "profile_id")
    private Profile profile;
}

@Entity
public class Profile {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String bio;
}

일대다(One-to-Many) 관계

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @OneToMany(mappedBy = "user")
    private List<Post> posts = new ArrayList<>();
}

@Entity
public class Post {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;

    private String content;
}

다대다(Many-to-Many) 관계

@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToMany
    @JoinTable(
        name = "student_course",
        joinColumns = @JoinColumn(name = "student_id"),
        inverseJoinColumns = @JoinColumn(name = "course_id")
    )
    private Set<Course> courses = new HashSet<>();
}

@Entity
public class Course {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToMany(mappedBy = "courses")
    private Set<Student> students = new HashSet<>();
}

 

4. 즉시로딩과 지연로딩

즉시로딩 (Eager Loading)

즉시로딩은 엔티티가 로딩될 때 연관된 엔티티도 즉시 함께 로딩되는 방식입니다. 연관된 엔티티를 즉시 필요로 하는 경우 유용하지만, 불필요한 데이터까지 로딩할 수 있어 성능 저하를 초래할 수 있습니다.

@Entity
public class User {
    @OneToMany(fetch = FetchType.EAGER, mappedBy = "user")
    private List<Post> posts;
}

 

지연로딩 (Lazy Loading)

 

지연로딩은 연관된 엔티티가 실제로 접근될 때 로딩되는 방식입니다. 초기 로딩 시 불필요한 데이터를 로딩하지 않아 성능을 최적화할 수 있습니다. 단, 연관된 데이터를 사용하기 전에 트랜잭션이 종료되면 LazyInitializationException이 발생할 수 있습니다.

 

@Entity
public class User {
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
    private List<Post> posts;
}

 

5. 로딩 전략 선택 시 고려사항

 

  • 성능: 즉시로딩은 필요하지 않은 데이터를 로딩하여 성능에 영향을 줄 수 있습니다. 지연로딩은 필요한 데이터를 나중에 로딩하여 초기 로딩 시간을 줄일 수 있습니다.
  • 트랜잭션 범위: 지연로딩을 사용할 때는 데이터가 사용되기 전까지 트랜잭션이 유지되어야 합니다. 트랜잭션이 종료되면 LazyInitializationException이 발생할 수 있습니다.
  • 사용 빈도: 자주 사용되는 연관 데이터는 즉시로딩을 사용하여 편의성을 높일 수 있습니다. 드물게 사용되는 데이터는 지연로딩을 사용하여 초기 성능을 최적화할 수 있습니다.

 

6. 예제 코드

지연로딩 예제

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
    private List<Post> posts;
}

@Entity
public class Post {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;

    private String content;
}

// 서비스 클래스
@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;

    @Transactional
    public User getUserWithPosts(Long userId) {
        User user = userRepository.findById(userId).orElseThrow(() -> new RuntimeException("User not found"));
        // 지연로딩된 posts를 명시적으로 초기화
        Hibernate.initialize(user.getPosts());
        return user;
    }
}

// 테스트 코드
@Test
public void testLazyLoading() {
    UserService userService = new UserService();
    User user = userService.getUserWithPosts(1L);
    // posts에 접근하면 지연로딩이 발생
    for (Post post : user.getPosts()) {
        System.out.println(post.getContent());
    }
}

 

7. 요약

  • 엔티티 연관관계: JPA는 엔티티 간의 연관관계를 지원하며, 이를 통해 객체 지향적으로 데이터를 처리할 수 있습니다.
  • 즉시로딩(Eager Loading): 연관된 엔티티를 즉시 로딩하는 방식으로, 초기 로딩 시 모든 데이터를 함께 로딩합니다.
  • 지연로딩(Lazy Loading): 연관된 엔티티를 실제로 접근할 때 로딩하는 방식으로, 초기 로딩 시 불필요한 데이터를 로딩하지 않습니다.
  • 로딩 전략 선택: 성능, 트랜잭션 범위, 사용 빈도를 고려하여 적절한 로딩 전략을 선택해야 합니다.