데브코스 백엔드 3기 55일차

2주만에 돌아온 TIL 작성하기 ㅎㅎ
그동안 개인플젝 + 바우처 웹과제 기간이었다
오랜만에 강의를 들은 월화수!
JDBC, MyBaits, JPA를 배웠다!


  • Application layer에서 Database layer에 접근하는 방법
    1. JDBC template
    2. Query mapper(MyBatis)
    3. ORM(JPA)


JPA

  • starter package -> auto configuration
    => 기본적인 JPA 설정들 해줄 수 있음
  • JPA는 Entity 객체를 생성할 때 기본생성자 사용 -> 기본생성자를 꼭 만들어주자
  • JPA 사용 위해 필요한 Java Bean 4개
    = auto-configuration 사용하면 자동으로 올리는 빈들
    • DataSource
    • 어떤 구현체 사용하는지 결정(JPA는 interface -> hibernate)
    • EntityManagerFactory : EntityManager
    • TransactionManager : @Transactioanl 관리위한 빈



EntityManagerFactory

  • EntityManager 생성
  • Thread-safe


제목 없음

사진출처

  • EntityManager
    • Entity 관련 모든일 처리(저장, 수정, 삭제, 조회 등)
      • Entity를 영속성 컨텍스트에 보관하고 관리
    • Thread-safe 하지 않음 -> EntityManagerFactory가 계속 새로운 EntityManager 생성해 단일 쓰레드 접근하도록
    • 사용하는 순간에 connection 가져옴
      = 트랜잭션 시작할 때 connection 획득



Persistence Context 영속성 컨텍스트

JPA 이용하는데 가장 중요한 요소

  • Entity를 영구 저장하는 환경
    • persist() = 영속화 시키겠다
  • 식별자값 필수 : 1차캐시를 활용하는데 이 때 key(id값) - value로 Entity 관리하니까
  • transaction commit 순간 flush => Entity가 Persistence Context -> DB 에 반영 = 동기화



Entity 생명주기

제목 없음y

  • 비영속 new/transient : 영속성 컨텍스트와 전현 관계없음
  • 영속 managed : 영속성 컨텍스트에 저장 상태
  • 준영속 detached : 영속성 컨텍스트에 저장 되었다가 분리 상태
  • 삭제 removed : 분리 + 삭제된 상태


저장
1) EntityManager 생성
2) EntityTransaction 획득 + Transaction 시작
3) 객체 생성 -> 비영속 상태
4) persist(객체) -> 영속화 상태 = 쓰기지연 저장소에 쿼리저장 + 1차 캐시에 저장
5) Transaction commit => flush = 쓰기지연 저장소에 있던 INSERT Query가 날아감 + DB와 동기화


조회

  • 1차 캐시를 이용한 조회
    • find() -> 1차캐시에서 조회 후 있으면 DB까지 안가고 1차캐시에서 결과 반환(SELECT Query 실행 안함)
  • DB 이용한 조회
    • clear() 후 find()
      -> 영속성 컨텍스트에서 관리되던 모든 엔티티들이 준영속상태가 되었으므로 1차캐시에 없음
      -> DB에 SELECT Query + 조회
      -> 1차 캐시에 저장 후 결과반환


수정

  • EntityManager의 이점 : 변경감지 = Dirty Checking (영속상태의 Entity에만 적용)

제목 없음y

1) 저장에서의 1) ~ 5)
2) find() -> set()
3) Transaction commit => flush, 스냅샷과 Entity 비교해서 변경내용 있으면 UPDATE Query

(스냅샷 : 최초로 영속성 컨텍스트(1차캐시)에 들어오는순간 스냅샷을 찍어서 저장해둠)


삭제
1) 저장에서의 1) ~ 5)
2) find() -> remove()
3) Transaction commit => flush + DELETE Query



Database schema 자동 생성

  • hibernate.hbm2ddl.auto
    • application 실행 시점에 데이터베이스에 맞는 적절한 DDL을 자동으로 생성
    • 이렇게 생성된 DDL은 개발 로컬 장비에서만 사용



Entity Mapping

Entity - Table mapping

  • @Entity : 이 객체는 영속성 컨텍스트에서 관리할 수 있는 객체임을 나타냄
    • DB에 저장하고 싶은 field에는 final 사용불가
  • @Table : Entity와 매핑할 table 지정


Field - Column mapping

  • @Id : 기본 키 매핑
  • @Column : column mapping
  • @Enumerated : enum type mapping
  • @Lob : 긴 내용
  • @Transient : mapping 무시
  • @Temporal : 날짜 type mapping


연관관계 매팽

  • Table : 외래키로 연관관계
  • 객체 : 참조(주소)로 연관관계


  • 방향성 : 단방향, 양방향
    (편의상 양방향 연관 관계, but Java에서 보면 서로 다른 단방향 관계 2개를 이은것)
  • 연관관계 주인 : 외래키 관리할 객체(테이블에 FK 있는 쪽)
    • 주인이 아닌 쪽은 mappedBy 속성을 통해 나타냄


  • 한명의 고객은 여러개의 주문을 가짐
  • 고객 기준 일대다 Member의 orders(List) 필드에 @OneToMany(mappedBy="member")
    (이 때의 member는 Order entity의 Member를 참조하는 필드이름
  • 주문 기준 다대일 @ManyToOne
  • 연관관계 편의 method 만들면 편함
    • ex)
      • Member 객체에 : addOrder(Order order)
      • Order 객체에 : Member 받았을 때 member.getOrders().add(this) 해주는 setMember(Member member)



고급매핑

  • @Inheritance(strategy = InheritanceType.SINGLE_TABLE) : 상속관계 지원
    • 부모 객체에 abstract class + @Inheritance + @DiscriminatorColumn(name = "DTYPE") 붙여주기
    • 자식 객체에 @DiscriminatorValue("부모객체")
    • strategy = JOINED도 있으나 SINGLE_TABLE이 하나의 테이블로 관리하기 쉬워 많이씀
  • @MappedSuperclass : 공통되는 필드들(ex) 생성일자) 따로 빼서 BaseEntity로 -> extends BaseEntity
  • 복합키를 식별자로 사용
    • @EmbeddedId를 Parent class의 id 필드에 + @Embeddable을 ParentId class에 => 많이씀, 객체지향스러움
    • Parent class에 @IdClass 붙이고 id1, id2 + ParentId class는 public, 기본생성자, equals&hashCode 구현, Serializable interface 구현


Lazy loading

@ManyToOne(fetch = FetchType.LAZY)

  • default : FetchType.EAGER
    • Order 불러올 때 바로 join해서 Member 사용전부터 가져옴(proxy 객체 사용안함)
  • Lazy fetch를 통해 Lazy loading 가능
    • order.getMember() 까지는 Member 객체가 JPA에서 proxy 객체라는 것으로 매핑
    • order.getMember().getNickname 처럼 Member 객체가 사용될 때 그 때 DB에서 가져와서 Entity가 됨

    => JPA proxy 객체로 객체탐색을 자유롭게 하기 위해 필요한 시점에 Query + Entity화
    (객체그래프 탐색 : 객체의 참조를 통해서 서로를 가져옴)


Proxy 특징

  1. 프록시객체는 처음 사용할 때 한번만 초기화됨
  2. 프록시객체 초기화 -> 프록시객체 통해 실제 엔티티 접근 가능
  3. 초기화는 영속성 컨텍스트의 도움받아야 가능
    (준영속 상태의 프록시 초기화 -> LazyInitializationException)



영속성 전이

  • Order 삭제하고 그안의 Member 객체 삭제하려면?
    • Order의 member 필드에 @ManyToOne(cascade = CascadeType.ALL)



고아객체

  • 부모 엔티티와 연관관계가 끊긴 자식엔티티를 자동으로 삭제하려면?
    • ex) 하나의 주문에 여러개의 주문상품들, 주문상품 입장에서 주문은 부모엔티티
      • Order의 orderItems 필드에 @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
        -> order를 remove() 하면 flush 순간 orderItems도 RDS에서 삭제
      • orphanRemoval default : false



라이브세션) 객체지향 언어의 이해

  • 우아한 형제들 강홍구 개발자님의 세션, 현재 JPA 강의도 해주시고 있는!

  • 객체지향 : 데이터 + 데이터를 조작하는 코드(프로시저)를 하나의 객체형태로 묶음
    -> 서로 연결 + 메시지 주고받음
    => 소프트웨어 구성

  • 의존 : 객체가 다른 객체의 기능을 이용해서 자신의 기능을 완성(ex) 흐름제어 객체)
  • 서로 의존하면서, 변화를 감추면서 소프트웨어를 만들어야함
    • 의존성 전이 : 의존하는 객체에게까지 변화를 끼침
    • 변경 많은 것 = 구체적인 것 = 저수준 모듈은 의존 안하는 편이 -> 유지보수위해
  • 캡슐화
    • SRP : 객체가 단일책임
    • ISP : 클라이언트마다 특화된 인터페이스 구현

    => 객체가 커지는것 막아줌

  • OCP가 핵심!
    • OCP를 할 수 있게 해주는 support 해주는 개념 : DIP, LSP
    • DIP : 자주 변경되는 부분을 추상화하자
    • LSP : 다형성을 이용하자

    => 기능확장 용이, 기존코드 변화는 적게



일기(회고)

  • 지난주 목금 데브코스 방학이었는데
    개인플젝 밀린 나는 방학을 가지지 못하고
    게더를 들어갔는데 동지들이 있었다!
    • 고독한 코딩방을 함께했다(룰도 없음서 룰엄수하라며)
      우리 뭔가 귀엽고 웃겨가지구 찍어놓음ㅋㅋㅋ
    • 아무도 안볼듯 하지만? 혹시나,,
      본인의 이름을 지워달라 하는 분은 말해주실,,

    1202


  • 2주동안 과제랑 개인플젝이랑
    정말 방학인줄알고 잡아둔 약속들 덕에
    무리하다가 몸져 누웠다,,
    세션듣다가 진짜 오한와서 덜덜 떨었다
    공부도 좋지만 건강 최고!


  • 개인플젝하면서 배운것들이나 에러는 따로 정리해야겠다
    이미 오늘 TIL은 너무 뚱뚱쓰!
    훈팀 테코톡은 하루에 하나씩 잘 듣고있고,
    오늘부터 좀 무리해서 CS 하루에 하나씩 질문 정리하기로!
    요것도 잘해보자~~


  • 훈팀 미팅
    • path vs query param : 도메인과 직접적으로 관련된 ID 같은 것들은 Path 파라미터로 처리하고 그외의 것들은 쿼리 파라미터로 사용하는 편
    • Null 객체 패턴 : null 대신 빈 객체를 보내자
    • 일급 컬렉션
      • 중복 코드 방지
      • 클래스를 한 번 더 Wrapping 한다고 생각하면 좋음


업데이트: