ETC/영상

[영상요약] 스프링 부트와 JPA활용 1편 요약

내가 그린 코딩 그림 2023. 1. 3. 01:28
반응형
실전! 스프링 부트와 JPA 활용 1편 - 인프런(김영한) 강의 내용 요약입니다.

 

싱글테이블 전략

설계 시 싱글테이블 전략을 사용했다. 종속 관계에 있는 테이블들을 그냥 합쳐버리고 구분값(DTYPE)을 준 것

 

★★외래키가 있는 곳을 연관관계의 주인으로 정하라

회원이 우선이니까 연관관계 주인으로 해야지~ 이런게 아닌 외래키가 있는 걸 주인으로 하라. 회원, 주문 테이블이 있다면 주문을 주인으로 따라서, 일대다 매핑이라면 ‘多’ 인 곳에 일대일 매핑이라면 접근을 더 많이하는 쪽에 넣으면 된다.

 

★실무에서는 many to many 사용안하는거 추천

실무에서 쓰게되면 문제가 많다 따라서 db에서 중간 테이블을 하나 넣어서 관리하는게 좋다.

 

★★Setter를 주의하자

변경포인트가 많아져 유지보수가 어려워진다.

setter의 경우 추후 수정시 엔티티가 대체 어디서 수정됐는지 일일히 찾아야하기 때문에 가급적 최~대한 지양하는 것이 좋다. getter의 경우 값을 바꾸는게 아니기 때문에 괜찮지만 setter는 주의해서 사용해야 한다.(예제에선 그냥 쓸 것)

 

jpa는 foreign key를 알아서 지정해준다.

정확도가 아닌 정말 빠른 속도만 원하는 경우는 외래키를 빼는 것을 고려해야하지만 그런게 아니라면 foreign key를 쓰는 것이 보통이다.

 

id컬럼을 정하는 규칙

단순히 id라고 하면 찾기가 어렵기 때문에 member테이블의 id면 member_id 라고 짓는게 관례상 좋다. foreign key랑 엮이기도 하기 때문에

 

★★값 타입은 변경 불가능하게

값 타입은 세터를 제거하고 생성자에서 값을 모두 초기화해서 변경 불가능한 클래스를 만들어준다. 기본생성자를 protected로 설정 코드상에서는 Address 클래스 살펴보면 된다.

  1. 세터 없이
  2. 기본생성자 만들고 protected로

 

JPA가 테이블을 만들어주긴하지만

JPA가 테이블을 생성해주지만 당연히 그대로 쓰는게 아닌 상황에 맞게 DDL을 활용해야한다.

 

★★★모든 연관관계는 지연로딩(LAZY)으로 설정해야한다.

수많은 에러를 해결해주는 문장이다.

즉시로딩(EAGER)은 예측이 어렵고 어떤 SQL이 실행될지 추적이 어렵다. 즉시로딩은 연관된걸 모두 끌고오기 때문에 하나 로딩하는데 모두를 끌고와져버려 문제가 발생하는 경우가 굉장히 많다. 특히, JPQL을 실행할 때 N+1문제가 자주 발생한다. 연관된 엔티티를 함께 DB에서 조회해야 한다면 fetch join을 사용하면 된다.

기본 패치전략은 다음과 같기 때문에

one to many → LAZY

many to one → EAGER

one to one → EAGER

모든 ~~ to one은 반드시. LAZY로 바꿔줘야한다.

 

컬렉션은 필드에서 초기화 하자

컬렉션은 필드에서 바로 초기화 하는 것이 가장 안전하다.

아래와 같은 두가지 방법 중 1번을 적용하면 null 걱정을 안해도 되고 메모리도 큰 차이가 없기 때문에 1번 방법을 권장한다.

//1번(권장방법)
private List<Order> orders = new ArrayList<>();

//2번
private List<Order> orders;

public Member(){
	oders = new ArrayList<>();
}

또 다른 이유는,

하이버네이트가 엔티티를 영속화 할 때 컬렉션을 감싸면서 하이버네이트가 제공하는 내장 컬렉션으로 변경된다. 만약 이미 내장 컬렉션으로 변경된 것에 getOrders() 처럼 임의 메소드에서 컬렉션을 잘못 생성하면 하이버네이트 내부 메커니즘 문제가 발생할 수 있다.

Member member = new Member();
System.out.println(member.getOrders().getClass());
em.persist(team);
System.out.println(member.getOrders().getClass());

// 출력 결과
class java.util.ArrayList
class org.hibernate.collection.internal.PersistentBag

 

하이버네이트 기본 테이블 엔티티 전략

직접 테이블 엔티티를 지정할 수 있으나 기본적인 하이버네이트 엔티티 전략이 존재한다.

스프링 부트 신규 설정(엔티티(필드) → 테이블(컬럼))

  1. 카멜케이스 → 언더스코어(userName → user_name)
  2. 점(.) → (언더스코어)
  3. 대문자 → 소문자

논리명의 경우 spring.jpa.hibernate.naming.implict-strategy를 바꿔서 커스텀하여 적용 가능(테이블에 컬럼명을 적지 않았을 때 규칙)

물리명의 경우 spring.jpa.hibernate.naming.physical-strategy를 바꿔서 커스텀하여 적용 가능(모든 논리명에 추가로 더하는 개념 모든 테이블 컬럼에 xx를 붙인다든지 등등)

 

JPQL

SQL과 매우 흡사하다.

SQL은 테이블 대상으로 쿼리를 하는 반면, JPQL은 엔티티 객체를 대상으로 쿼리를 한다.

 

JPA의 롤백

JPA는 기본적으로 롤백을 하는데, 여기서 롤백이란 insert하고 롤백하는 것이 아닌 그냥 insert 자체를 안해버리는(flush) 것이기 때문에 테스트 케이스에서 Rollback(false) 어노테이션을 안주게 되면 insert 쿼리문 자체가 안보이게 된다.

만약 롤백이지만 그래도 쿼리문을 보고 싶다면?

⇒ 아래와같이 넣어주면됨

 

Try, Catch로 빠져야하는 테스트문

왼쪽 코드를 오른쪽처럼 바꿀 수 있다.

 

h2메모리 디비로 테스트

외부 디비를 이용해서 테스트를 하는건 꽤나 번거롭다. 따라서 스프링부트에서 h2 메모리디비를 활용해 테스트하는 방법을 제공한다.

  1. test에 resources 디렉토리를 만든다
  2. resources에 application.yml을 추가한다(기본적으로 테스트는 테스트쪽에 resources가 있으면 이를 우선적으로 한다.)
  3. 디비 경로를 다음과 같이 바꿔준다
jdbc:h2:mem:test

  4. 하지만 사실 스프링부트는 별도 설정이 없어도 메모리모드로 다 돌려버린다. 따라서, application.yml에는 다음과 같이 필요한 로깅만 해놓으면 된다.

spring:

logging.level:
  org.hibernate.SQL: debug
  org.hibernate.type: trace

 

스프링부트는 기본적으로 create-drop으로 돌아간다

drop으로 확실하게 자원정리까지 하게 되어있다.

 

JPA 큰 장점

주문 취소를 하는 상황 같은 경우 원래 같으면 sql을 다 작성해서 주문이 들어가는 로직을 넣고, 주문 취소를 하면 주문이 취소되는 로직을 넣는 등 가능하지만 jpa의 경우 더티체킹을 통해서 변경된점을 알아서 잘 찾아 넣는다 ⇒ 아직 이해못했는데 중요한 부분 같음

 

도메인 모델 패턴

Service 계층은 엔티티에 비지니스 로직을 위임받아 한다. 실제 구현하는 기능은 없다. 이런 경우 도메인 모델 패턴이라 한다. 반대로 엔티티에 비지니스 로직이 거의 없고 서비스 계층에서 대부분의 로직을 처리하는 것을 트랜잭션 스크립트 패턴이라고 한다(보통 내가 하던것으로 그래서 어색한 느낌이 드는 거였음)

 

김영한님이 꼭 가져가는 것

  1. 스프링부트
  2. JPA, DATA JPA
  3. Querydsl

이렇게 꼭 함께 가져가야 실무에서 항상 써먹을 수 있다.

 

에러처리(binding result)

binding result를 통해서 오류가 나면 다시 그 페이지로 돌려주면서 깔끔하게 오류문을 뿌려줄 수 있다.

MemberController 참고, 영상은 회원등록 참고

 

다음과 같은 장점이 존재

  1. 에러를 간단하게 뿌려줄 수 있다는 점(ex: 회원 이름은 필수입니다)
  2. 기존의 데이터를 유지하고 있다는 점

 

★★엔티티를 최대한 보존해야 한다.

회원가입 처리를 할 때도 엔티티를 건드리지 않고 form 객체를 만들어서 하는데 서비스 규모가 매우 작고 단순하다면 괜찮지만 정말 웬만해서는 form 객체로 하는 것이 좋다.

 

엔티티를 화면에 뿌려주기 위한건 없어야 한다. 화면은 form 객체나 dto를 건드리는게 낫다.

특히 api를 만들 때 엔티티를 넘기면 절대절대 안된다.

 

현재 memberList.html에서는 엔티티를 그대로 받아서 보여주게되는데(/members 매핑 된 부분) 이것도 사실 없애는게 가장 좋다 이번에는 그냥 엔티티를 정말 바꿀게 하나도 없어서 쓴거뿐

 

★★★수정의 2가지

정말 중요한 파트

  • 변경감지(dirty checking) → best

변경된 것이 있으면 JPA가 변경점을 찾는다

  • 병합(merge) → 베스트는 아님

준영속 엔티티란

영속성 컨텍스트가 더 이상 관리하지 않는 엔티티를 뜻한다 이미 데이터가 DB에 갔다오면 식별자가 생긴개념이기 때문에 영속성 컨텍스트가 더 관리하지 않는다.

준영속 엔티티를 수정하는 2가지 방법

  • 변경 감지 기능 사용
  • 병합(merge) 사용

주의할 점 : 변경 감지 기능을 사용하면 원하는 속성만 변경이 가능하지만 병합(merge)을 사용하멱 병합 시 값이 없으면 null로 업데이트 될 위험이 있다. 따라서, merge가 아닌 변경 감지를 해야한다.
반응형