1-6 데이터베이스 테이블 간의 객체 간의 관계

릴레이션 오브젝트 = ORM (Object-Relational Mapping), FetchType.LAZY와 FetchType.EAGER
홍윤's avatar
Aug 20, 2024
1-6 데이터베이스 테이블 간의 객체 간의 관계

1. 릴레이션 오브젝트 = ORM (Object-Relational Mapping)

💡
"릴레이션 오브젝트"라는 용어는 "관계형 객체" 또는 "릴레이션 객체"로 해석될 수 있으며, 주로 데이터베이스와 객체 지향 프로그래밍 사이의 관계를 설명할 때 사용됩니다. 이 개념은 데이터베이스 테이블 간의 관계와 객체 간의 관계를 연결짓는 것을 의미합니다. 가장 일반적으로는 **ORM(Object-Relational Mapping)**과 관련된 용어로 사용됩니다.
 

주요 개념:

  1. ORM (Object-Relational Mapping):
      • 객체 지향 프로그래밍 언어에서 데이터베이스 테이블을 객체로 매핑하는 기술입니다. 예를 들어, 데이터베이스의 테이블을 클래스와 매핑하고, 테이블의 레코드를 객체로 다루게 됩니다.
      • Entity: 데이터베이스 테이블에 대응하는 클래스입니다.
      • Relationship: 엔티티 간의 관계로, 데이터베이스 테이블 간의 관계(1:1, 1, N)가 클래스 간의 관계로 표현됩니다.
  1. Entity Relationship:
      • 1:1 관계: 두 테이블이 1:1 관계를 가지며, 각각의 레코드가 서로 하나의 레코드에만 연결됩니다. 예를 들어, UserProfile 클래스가 있을 때, 각각의 User는 하나의 Profile만 가질 수 있습니다.
      • 1관계: 한 테이블의 한 레코드가 다른 테이블의 여러 레코드와 연결되는 관계입니다. 예를 들어, UserOrder 클래스가 있을 때, 한 User는 여러 Order를 가질 수 있습니다.
      • N관계: 두 테이블 간에 여러 레코드가 서로 연결될 수 있는 관계입니다. 이를 표현하기 위해 보통 연결 테이블이 사용됩니다. 예를 들어, StudentCourse가 N관계일 때, 각 학생은 여러 수업을 듣고, 각 수업은 여러 학생이 들을 수 있습니다.
  1. 예시 (Java & JPA):
      • Entity 클래스 정의:
        • java코드 복사 @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; @OneToOne private Profile profile; // 1:1 관계 @OneToMany(mappedBy = "user") private List<Order> orders = new ArrayList<>(); // 1:N 관계 } @Entity public class Profile { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String bio; } @Entity public class Order { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String product; @ManyToOne @JoinColumn(name = "user_id") private User user; // N:1 관계 }
      • Database Table:
        • User 테이블은 Profile과 1:1 관계, Order와 1관계를 가집니다.
        • Profile 테이블은 User와 1:1 관계를 가집니다.
        • Order 테이블은 User와 N:1 관계를 가집니다.

정리:

"릴레이션 오브젝트"는 객체 지향 프로그래밍에서 데이터베이스 테이블 간의 관계를 객체로 표현한 개념입니다. ORM 프레임워크는 이러한 관계를 쉽게 다룰 수 있도록 도와주며, 엔티티 간의 관계를 정의하고 관리하는 역할을 합니다. 이를 통해 개발자는 데이터베이스의 복잡한 관계를 객체 지향적으로 쉽게 다룰 수 있게 됩니다.
 
Board
package shop.mtcoding.blog.board; import jakarta.persistence.*; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import shop.mtcoding.blog.user.User; import java.sql.Timestamp; @NoArgsConstructor // 빈 생성자 (하이버네이트가 om 할때 필요) @Setter @Getter @Table(name = "board_tb") @Entity // DB에서 조회하면 자동 매핑이됨 public class Board { @GeneratedValue(strategy = GenerationType.IDENTITY) // auto_incremnt 설정, 시퀀스 설정 @Id // PK 설정 private Integer id; @Column(nullable = false) private String title; @Column(nullable = false) private String content; private Timestamp createdAt; //fk N한테 FK를 만들어야한다. //User table 에 select 를 한 번더 돌린다. @ManyToOne(fetch = FetchType.LAZY) @ManyToOne(fetch = FetchType.EAGER) private User user; @Builder public Board(Integer id, String title, String content, Timestamp createdAt) { this.id = id; this.title = title; this.content = content; this.createdAt = createdAt; } }
💡
@ManyToOne(fetch = FetchType.LAZY)@ManyToOne(fetch = FetchType.EAGER)는 JPA에서 엔티티 간의 다대일 관계를 정의할 때 사용하는 애노테이션으로, 이 두 가지는 연관된 엔티티를 로딩하는 방식에 차이가 있습니다.

FetchType.LAZYFetchType.EAGER 비교

  1. 지연 로딩 (FetchType.LAZY)
      • 설명: 연관된 엔티티를 실제로 필요할 때까지 로드하지 않습니다. 즉, User 엔티티가 참조될 때까지 데이터베이스에서 User 엔티티를 가져오지 않습니다.
      • 동작 방식:
        • 처음에 주 엔티티를 조회할 때 User 엔티티는 로드되지 않습니다.
        • User 엔티티가 실제로 접근될 때, 그때 비로소 데이터베이스에 select 쿼리가 실행되어 User 데이터를 가져옵니다.
      • 장점: 메모리 사용량이 줄고, 불필요한 데이터를 미리 로드하지 않으므로 성능이 최적화될 수 있습니다.
      • 단점: User 엔티티를 사용할 때마다 추가적인 데이터베이스 쿼리가 발생할 수 있습니다.
  1. 즉시 로딩 (FetchType.EAGER)
      • 설명: 연관된 엔티티를 주 엔티티와 함께 즉시 로드합니다. 즉, User 엔티티를 주 엔티티와 동시에 데이터베이스에서 가져옵니다.
      • 동작 방식:
        • 주 엔티티를 조회할 때, User 엔티티도 즉시 함께 조회됩니다.
        • 데이터베이스 쿼리는 주 엔티티와 User 엔티티를 함께 조회하여 한 번에 데이터를 가져옵니다.
      • 장점: 주 엔티티와 연관된 User 엔티티가 항상 필요할 때 유용하며, 추가적인 데이터베이스 접근이 없어 성능이 최적화될 수 있습니다.
      • 단점: 불필요한 데이터가 미리 로드될 수 있어 메모리 사용량이 증가할 수 있으며, 경우에 따라 성능이 저하될 수 있습니다. 특히 연관된 데이터가 많을 때 문제가 될 수 있습니다.

      사용 시기 비교

      • *FetchType.LAZY*를 사용하는 경우:
        • User 엔티티가 항상 필요한 것이 아니라 특정 상황에서만 필요할 때.
        • 불필요한 데이터 로딩을 피하고 메모리 사용을 최소화하고자 할 때.
        • 연관된 데이터가 크거나, 많은 엔티티와의 관계가 있는 경우.
      • *FetchType.EAGER*를 사용하는 경우:
        • 주 엔티티와 연관된 User 엔티티가 항상 필요한 경우.
        • 애플리케이션의 로직에서 User 엔티티를 자주 사용하는 경우.
        • 추가적인 데이터베이스 쿼리를 피하고, 처음부터 모든 데이터를 가져오는 것이 더 효율적일 때.

2.캐싱

💡
캐싱은 데이터나 객체를 미리 저장해두고, 이후에 필요할 때 빠르게 접근할 수 있도록 하는 기법입니다. 이를 통해 데이터베이스 조회나 계산이 반복될 때 성능을 크게 향상시킬 수 있습니다.
@ManyToOne 관계에서 캐싱을 사용하는 것은, 특히 fetch = FetchType.LAZY가 사용될 때 유용할 수 있습니다. 지연 로딩 시 매번 데이터베이스에 접근하지 않고, 한 번 로드한 데이터를 캐시에 저장해 두었다가 다시 사용할 수 있기 때문입니다.
JPA에서 캐싱을 사용하는 방법은 크게 1차 캐시와 2차 캐시로 나눌 수 있습니다:
  1. 1차 캐시:
      • JPA에서 기본적으로 제공하는 캐시로, 동일한 트랜잭션 내에서 동일한 엔티티를 다시 조회할 때 데이터베이스에 접근하지 않고 메모리에서 데이터를 가져옵니다.
      • 1차 캐시는 EntityManager 수준에서 관리되며, 트랜잭션이 끝나면 캐시가 사라집니다.
  1. 2차 캐시:
      • 애플리케이션 전역에서 엔티티를 캐싱하는 방법입니다. 2차 캐시는 애플리케이션이 종료되거나, 명시적으로 캐시를 지우기 전까지 유지됩니다.
      • 2차 캐시는 Hibernate에서 지원하며, Ehcache, Infinispan, Hazelcast 같은 외부 캐시 라이브러리와 통합하여 사용할 수 있습니다.
      • 이를 설정하면, 특정 엔티티가 한 번 데이터베이스에서 조회된 후 다른 트랜잭션이나 요청에서 동일한 엔티티가 필요할 때마다 데이터베이스를 다시 조회하지 않고 캐시된 데이터를 사용하게 됩니다.
캐싱을 적절히 사용하면, 데이터베이스 부하를 줄이고 애플리케이션의 응답 속도를 크게 향상시킬 수 있습니다. 하지만 캐시의 일관성을 유지하는 것과 캐시가 갱신될 때 발생할 수 있는 문제를 잘 관리하는 것이 중요합니다.
notion image

 
💡

강사님께서 알려주신 "N포드"의 의미와 용어 해석

N
관계를 다루는 조인 방식에서의 "포드"를 지칭하는 것으로 보입니다. 여기서 "포드"는 다음과 같은 의미를 가진다.
  • "N": 두 테이블 간의 관계에서 'N'은 여러 개의 레코드를 의미합니다. 즉, 두 테이블 간의 조인에서 각각 여러 개의 관련된 레코드가 있을 수 있음을 나타냅니다.
  • "포드": 이 부분은 "Join" 또는 **"Join Table"**과 관련된 개념으로, 여러 개의 레코드가 서로 연결될 수 있는 관계를 설명합니다.

N 관계 및 드라이빙 테이블

N관계다대다 관계를 의미하며, 두 테이블 간의 조인에서 많은 레코드가 서로 연결될 수 있는 관계입니다. 이 관계를 표현하기 위해
연결 테이블 (중간 테이블)을 사용합니다.

예시

  1. 학생(Student)과 수업(Course):
      • 학생은 여러 수업을 들을 수 있습니다.
      • 수업은 여러 학생이 수강할 수 있습니다.
      • 이 경우, 연결 테이블을 사용하여 이들 간의 관계를 정의합니다.
sql코드 복사 -- 연결 테이블 예시 CREATE TABLE Student_Course ( student_id INT, course_id INT, PRIMARY KEY (student_id, course_id), FOREIGN KEY (student_id) REFERENCES Student(id), FOREIGN KEY (course_id) REFERENCES Course(id) );

드라이빙 테이블

드라이빙 테이블은 SQL 쿼리에서 조인을 수행할 때 쿼리 최적화를 위해 선택된 첫 번째 테이블입니다. 드라이빙 테이블은 일반적으로 데이터 양이 적거나 인덱스가 잘 설정된 테이블로 선택됩니다.

종합 설명

  • N: 두 테이블 간의 관계에서 많은 레코드를 의미합니다.
  • 포드: 조인 또는 연결을 다루는 테이블로, N관계를 나타내는 연결 테이블을 의미합니다.
따라서, "N포드"는"N관계"*의 개념을 설명하기 위해 사용된 용어이다. 이를 통해 두 테이블 간의 다대다 관계를 표현하고, 관련된 데이터를 조회하는 방식과 그에 따른 드라이빙 테이블 선택의 중요성을 나타낼 수 있습니다.
 
 
Share article

Uni