Spring 4일차

TaeYoon Kim·2023년 12월 19일
0

SW CAMP

목록 보기
17/30

1교시 복습
Hibernate
Entity Manager가 중요하다.
Entity 클래스들은 기본 생성자를 가지고 있어야한다. (프록시 객체를 만들어야됨)

ORM에서 중요한 건 관계 맺는 것을 이해하는 것이다.
관계를 맺고 발생하는 문제들이 있다.
데이터 베이스에서 실행하는 것들을 자바에서도 똑같이 실행되도록 처리를 해줘야한다.

양방향관계를 맺은 선수와 팀이 있을 때 문제 예시
1. 선수 객체에 팀을 추가했을 때, 팀 객체의 선수리스트에 자동으로 추가 되지 않는 문제.
2. 선수객체의 팀을 교체했을 때, 전의 팀 선수리스트에 선수가 남아있는 문제

1번 문제
데이터 베이스에서 선수 테이블에 insert작업을 하면
팀 테이블에 추가로 작업해줘야하는 것이 없지만
자바 프로젝트 내에서는 팀 객체의 선수리스트에 선수 객체를 추가해야한다.

2번 문제
데이터 베이스에서 선수의 팀을 수정하는 것은 팀 테이블에 영향을 주지 않지만
자바 프로젝트에서는 팀 객체에 있는 선수를 삭제하고 다른 팀을에 추가하는 추가 과정이 필요하다.

위 예시를 보면 ORM을 이용해서 데이터 베이스와 매핑을 했다고 해도 자바 프로젝트 내에서 CRUD 작업을 진행할 때, 똑같이 작동한다고 생각하면 안된다. 왜냐고? 지연 쿼리를 이용하기 때문이다.

부록. one to many는 단독으로 쓰지마

2교시
JPA에서 가장 중요한 내용을 할 것이다.
SELECT 문에 관한 내용을 할 것이다.

  1. 즉시 로딩 지연 로딩(lazy loading) (Entity Manager의 지연 쿼리와 관계없음)
    엔티티를 조회할 때 연관된(관계를 설정한) 엔티티들이 항상 사용되는 것은 아니기 때문에 당장 사용하지 않을 엔티티는 바로 조회하는 것이 아니라 해당 엔티티가 사용되는 시점에 DB에서 조회하는 것을 지연 로딩이라고 한다.

데이터 베이스에서 정보를 찾아와 객체를 만들었다고 해도,
객체 안에 저장된 모든 값들을 이용하지 않는다. 그래서 필요할 때 꺼내오겠다는 설정이다.

기본 설정 값은 즉시 로딩, 관계 어노테이션에 전략을 추가해서 지연로딩 설정가능
ex) @ManyToOne(fetch = FetchType.lazy)
1) 프록시 객체 : 지연로딩 시, 다른 엔티티를 저장하는 변수에 저장되는 가짜 객체
프록시 객체에 접근하면 지연로딩이 일어난다.

3교시
실습 후

Spring data jpa 사용법
1. 외부 라이브러리 설정과 JPA 설정 파일 작성

spring:
  datasource:
    url: jdbc:mysql://192.168.72.30:3306/test
    username: kty
    password: qwer1234
    driver-class-name: com.mysql.cj.jdbc.Driver

  jpa:
    hibernate:
      ddl-auto: update
    properties:
      hibernate:
        format_sql: true
    show-sql: true
  1. 엔티티 클래스 만들기 (스프링 3일차 참조)
  2. repo 인터페이스 만들기
  3. 상속받기
@Repository
public interface ProductRepo extends JpaRepository<Product,Integer> { //<엔티티 클래스,기본키 타입>
}

스프링이 인터페이스도 객체로 알아서 만들어준다.
이제 의존성 주입해서 쓰기만 하면 된다.

주요 메스드 정리

  1. DTO클래스 만들기
  2. 서비스 클래스 만들기
  3. 컨트롤러 서비스 만들기

    4교시
    영화 CRUD 만들어보자
    5교시 풀이

6교시
영화 리뷰 CRUD를 추가해보자

연관 관계를 맺을 때 3가지를 생각해야한다.
1. 방향
2. 다중성
3. 주인

7교시 영화 리뷰 풀이
stackoverflow 에러가 나는 이유
Entity 객체를 그대로 반환해서 순환 참조 문제가 생겨버림.

에러가 안나게 만드는 방법
1. @JsonIgnore (쓰면 양방향 관계로 만드는 이유가 없음.)
2. Entity를 DTO로 변경 (보통 이걸로 씀.)

8교시
N+1 문제가 발생하는 모습을 보자.

영화 목록를 가져와 보자.
영화 테이블에 3개의 값이 들어가 있고
1번 영화 리뷰는 3개, 2번은 리뷰 1개, 3번은 0개이다.

Hibernate: 
    select
        movie0_.id as id1_0_,
        movie0_.name as name2_0_,
        movie0_.price as price3_0_ 
    from
        movie movie0_
Hibernate: 
    select
        reviews0_.movie_id as movie_id4_2_0_,
        reviews0_.id as id1_2_0_,
        reviews0_.id as id1_2_1_,
        reviews0_.movie_id as movie_id4_2_1_,
        reviews0_.star as star2_2_1_,
        reviews0_.text as text3_2_1_ 
    from
        review reviews0_ 
    where
        reviews0_.movie_id=?
Hibernate: 
    select
        reviews0_.movie_id as movie_id4_2_0_,
        reviews0_.id as id1_2_0_,
        reviews0_.id as id1_2_1_,
        reviews0_.movie_id as movie_id4_2_1_,
        reviews0_.star as star2_2_1_,
        reviews0_.text as text3_2_1_ 
    from
        review reviews0_ 
    where
        reviews0_.movie_id=?
Hibernate: 
    select
        reviews0_.movie_id as movie_id4_2_0_,
        reviews0_.id as id1_2_0_,
        reviews0_.id as id1_2_1_,
        reviews0_.movie_id as movie_id4_2_1_,
        reviews0_.star as star2_2_1_,
        reviews0_.text as text3_2_1_ 
    from
        review reviews0_ 
    where
        reviews0_.movie_id=?

총 4번의 sql이 실행된 모습이다.
모든 영화를 영화 테이블에서 검색한 후 영화의 수만큼 리뷰를 찾아본 것이다.

우리가 모든 영화를 조회하는 쿼리를 직접 짠다면 아마 Join를 이용할텐데
비효율적인 코드가 실행되는 모습이다.

거기다 영화목록 조회는 이용자 대부분이 사용하는 문제일텐데...
이건 내일 해결해보자.

0개의 댓글