TIL - JPA 데이터베이스 (25.04.30)

kb·2025년 4월 30일

Spring

목록 보기
18/21

2-4 데이터베이스 연결(Driver)

  • JDBC Driver Manager의 역할
    • Application과 DB 간의 통신을 중개.
    • 우체부가 편지를 전달하는 것처럼, Driver는 Application의 요청을 DB가 이해할 수 있는 언어로 변환
  • DB Driver의 동작 (개요)
    • 항공 교통 관제 시스템과 유사. Application과 DB간의 데이터 교환을 조절하고 관리하는 역할
  • Driver 동작 방식
    • 연결 초기화 > SQL 전송 및 실행 > 결과 처리 > 연결 종료 순서로 동작
  • JDBC Driver Manager는 Application이 실행되고 있는 런타임 시점에
    1) Connection(연결)을 생성해 쿼리를 요청할 수 있는 상태를 만들어주고
    2) Statement(상태)를 생성해 쿼리를 요청하게 해주고
    3) ResultSet(결과셋)을 생성해 쿼리 결과를 받아올 수 있게 해줌
    4) 위의 세 가지 상태는 꼭 기억하라고 함!

2-5 데이터베이스 데이터를 외부에서 다루기(JDBC)

  • Spring Boot의 JDBC 라이브러리
    • Spring Boot는 데이터베이스 연결을 쉽게 구성할 수 있도록 다양한 JDBC 드라이버를 지원 > 복잡한 설정 없이 데이터베이스와의 연결을 쉽게 구성
  • JDBC Template (QueryMapper)
    • JDBC로 직접 SQL 작성 시 SQL쿼리 요청 시 중복 코드 발생
    • DB별 예외에 대한 구분 없이 Checked Exception (SQL Exception) 처리
    • Connection, Statement 등 자원 관리를 따로 해줘야 (자원 해제를 안하면 메모리 꽉차서 서버가 죽음)
    • 이 문제 해결을 위해 Persistence Framework 2가지가 등장
    • 1) SQL Mapper : JDBC Template, MyBatis
    • 2) ORM : JPA, Hibernate
  • JDBC Template (RowMapper)
    • SQL Mapper 첫번째 주자로 JDBCTemplate에 RowMapper 탄생
    • 쿼리 수행 결과와 객체 필드 매핑
    • RowMapper로 응답필드 매핑코드 재사용
    • Connection, Statement, ResultSet 반복적 처리 대신
    • But, 결과값을 객체 인스턴스에 매핑하는데 여전히 많은 코드 필요

3-2 쿼리 파일 만들기(QueryMapper)

  • QueryMapper의 DB의존성 및 중복 쿼리 문제로 ORM이 탄생
    • MyBatis > RowMapper가 갖고 있는 단점인 "반복 코드"를 줄이고 "함께있는 프로그램 코드와 쿼리 코드를 분리하여 관리"하기 위해 탄생
    • SQL Mapper의 두 번째 주자 ... SQL 쿼리들을 XML 파일에 작성해 코드와 SQL을 분리하고 싶다...
    • 코드의 설정(Connection) 부분을 줄이고 실제 sql문에 연결 > 빠른 개발 가능
    • map 인터페이스(또는 클래스)와 SQL 쿼리와 ResultSet 매핑을 위한 xml 및 annotation을 사용.
    • 한계: 결국 SQL을 직접 작성하는 건 피곤 (DB기능에 종속적) / 테이블마다 비슷한 CRUD 반복. DB 타입 및 테이블에 종속적
  • ORM이 해결해야하는 문제점과 해결책
    • 문제점: 상속 / 관계 / 탐색 / 밀도 / 식별성
    • 해결책: 영속성 컨텍스트(1차 캐시)를 활용한 쓰기지연
    • flush() 전까지 최적화. flush()로 전송된 쿼리는 더 이상 최적화되지 않고 commit()으로 반영만 가능.
    • 쓰기 지연 효과: 쿼리를 한 번에 전송 / 트랙잭션 종료 시 쿼리는 1번만 전송 / 영속성 상태에서 객체가 생성되었다 삭제되면 실제 DB에는 아무 동작이 전송되지 않을 수 있음
    • 즉, 여러가지 동작이 많이 발생해도 쿼리는 트랜잭션당 최적화 되어 최소쿼리만 날라감
  • ORM을 사용하는 가장 쉬운 방법: JpaRepository
    • JpaRepository< Entity, ID> 인터페이스를 인터페이스에 extends 붙임 ... @NoRepositoryBean 된 상위 인터페이스들의 기능을 포함한 구현체가 프로그래밍 됨(빈 생성을 막고, 상속받으면 생성돼서 사용 가능한 Annotation)
    • JpaRepository (마스터 셰프) : 데이터 엑세스를 위한 핵심 기능의 종합적인 요리책(기능)을 제공
    • @NoRepositoryBean 인터페이스 (셰프) : 각 인터페이스는 특정 데이터 액세스 방법을 제공하는 전문적인 기술 또는 레시피를 나타냄
    • JpaRepository 상속 : 마스터 셰프의 요리책과 셰프의 전문성을 얻음
    • SpringDataJpa에 의해 엔티티의 CRUD, 페이징, 정렬 기능 메소드들을 가진 빈이 등록됨(상위 인터페이스들의 기능)

3-6 테이블 객체끼리 관계 만들기

  • OneToOne : 꼭 물리적으로 분리되어야 할까? 생각해볼 관계
  • OneToMany : 단방향으로 쓰이면 문제가 발생할 수 있다!
    • 속도를 위해 기본적으로 FetchType 설정이 LAZY임
    • 네 가지 속성을 가짐
      • mappedBy : 연관관계의 주인 필드를 선택
      • fetch : 글로벌 패치 전략 설정
      • cascade : 영속성 전이 기능 사용
      • targetEntity : 연관된 엔티티의 타입 정보를 설정
  • ManyToOne
    • 네 가지 속성을 가짐
      • optional (default true) : false로 설정하면 연관된 엔티티가 반드시 있어야 함
      • fetch : 글로벌 패치 전략 설정 (기본이 EAGER이나, 실무에서는 LAZY를 기본으로 설정하는 것을 추천)
      • cascade : 영속성 전이 기능 사용
      • targetEntity : 연관된 엔티티의 타입 정보 설정 (targetEntity = Member.class 식으로 사용)
  • JoinColumn
    • 외래 키 매핑 시 사용(Join을 요청하기 위한 매핑정보로 쓰임)
    • @ManyToOne 어노테이션과 주로 함께 쓰임(조인대상 컬럼 지정기능을 안 쓸거면 생략해도 됨)
    • name 속성은 매핑할 외래키의 이름
    • 어노테이션을 생략해도 외래 키가 생성됨
    • 네 가지 속성을 가짐
      • name : 매핑할 외래 키의 이름
      • referencedColumnName : 외래 키가 참조하는 대상 테이블의 컬럼명
      • foreignKey : 외래 키 제약조건 지정 (테이블 생성 시에만 적용)
      • unique/nullable/insertable/updateable/columnDefinition/table : @Column의 속성과 같음
  • ManyToMany
    • 다대다 설정을 하게 되면 중간 매핑테이블(JoinTable)이 자동으로 생성 됨
    • 중간 매핑 테이블은 JPA상에서 숨겨져서(Entity 정의 없이) 관리됨
    • 매핑 테이블 관리가 불가능해 실무에서는 잘 사용하지 않음
    • 실무에서는 매핑 테이블을 아래와 같은 형태로 직접 정의함
      • TableA(@OneToMany) > MappingTable(@ManyToOne, @ManyToOne) >TableB(@OneToMany)

연관관계 관련 의문

  • 배울 때는 @OneToMany Mapping보다 Many쪽에 연관관계의 주인 권한을 줘서 @ManyToOne 형태로 연관관계를 설정하는 경우가 많다고 배운 것 같아. 그리고 양방향 맵핑을 하면 데이터의 변경 시 상대쪽 테이블 중 어디에 변화를 줄 것인지에 대해 모호함과 어려움이 있다고 들은 것 같은데, 내가 어떤 부분을 놓치고 있는지 알려줄래?
  • Dr.G의 답변
  • 일단, 기존에 알고 있던 정보는 맞다고 함.
  • @OneToMany 맵핑은 객체 그래프 탐색과 조회 최적화에 도움을 주고, 양방향 관계는 '읽기 전용' 관계로 활용 가능
  • 연관관계의 주인을 Many 쪽에 두고, One 쪽은 read-only로 유지하면 변경 책임이 명확해져 실무에서 혼란이 줄어든다고 함!
  • 양방향 매핑이 무조건 나쁜게 아니라, 용도에 맞게 사용하는 것이 중요!
  • 추가 질문: @OneToMany에서(mappedBy = Many쪽 테이블 명) 이렇게 설정하는 건가?
  • @OneToMany(mappedBy = "...")에서 "..."은 Many쪽 테이블에 매핑되는 필드명을 쓴다고 한다! @OneToMany(mappedBy = "parent")라고 해서 parent 테이블 스스로를 참조하는 게 아니었구나!
profile
Experience

0개의 댓글