데브코스 백엔드 3기 55일차
2주만에 돌아온 TIL 작성하기 ㅎㅎ
그동안 개인플젝 + 바우처 웹과제 기간이었다
오랜만에 강의를 들은 월화수!
JDBC, MyBaits, JPA를 배웠다!
- Application layer에서 Database layer에 접근하는 방법
- JDBC template
- Query mapper(MyBatis)
- 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 획득
- Entity 관련 모든일 처리(저장, 수정, 삭제, 조회 등)
Persistence Context 영속성 컨텍스트
JPA 이용하는데 가장 중요한 요소
- Entity를 영구 저장하는 환경
- persist() = 영속화 시키겠다
- 식별자값 필수 : 1차캐시를 활용하는데 이 때 key(id값) - value로 Entity 관리하니까
- transaction commit 순간 flush => Entity가 Persistence Context -> DB 에 반영 = 동기화
Entity 생명주기
- 비영속 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차 캐시에 저장 후 결과반환
- clear() 후 find()
수정
- EntityManager의 이점 : 변경감지 = Dirty Checking (영속상태의 Entity에만 적용)
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)
- ex)
고급매핑
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
: 상속관계 지원- 부모 객체에 abstract class +
@Inheritance
+@DiscriminatorColumn(name = "DTYPE")
붙여주기 - 자식 객체에
@DiscriminatorValue("부모객체")
- strategy = JOINED도 있으나 SINGLE_TABLE이 하나의 테이블로 관리하기 쉬워 많이씀
- 부모 객체에 abstract class +
@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 특징
- 프록시객체는 처음 사용할 때 한번만 초기화됨
- 프록시객체 초기화 -> 프록시객체 통해 실제 엔티티 접근 가능
- 초기화는 영속성 컨텍스트의 도움받아야 가능
(준영속 상태의 프록시 초기화 -> LazyInitializationException)
영속성 전이
- Order 삭제하고 그안의 Member 객체 삭제하려면?
- Order의 member 필드에
@ManyToOne(cascade = CascadeType.ALL)
- Order의 member 필드에
고아객체
- 부모 엔티티와 연관관계가 끊긴 자식엔티티를 자동으로 삭제하려면?
- ex) 하나의 주문에 여러개의 주문상품들, 주문상품 입장에서 주문은 부모엔티티
- Order의 orderItems 필드에
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
-> order를 remove() 하면 flush 순간 orderItems도 RDS에서 삭제 - orphanRemoval default : false
- Order의 orderItems 필드에
- ex) 하나의 주문에 여러개의 주문상품들, 주문상품 입장에서 주문은 부모엔티티
라이브세션) 객체지향 언어의 이해
-
우아한 형제들 강홍구 개발자님의 세션, 현재 JPA 강의도 해주시고 있는!
-
객체지향 : 데이터 + 데이터를 조작하는 코드(프로시저)를 하나의 객체형태로 묶음
-> 서로 연결 + 메시지 주고받음
=> 소프트웨어 구성 - 의존 : 객체가 다른 객체의 기능을 이용해서 자신의 기능을 완성(ex) 흐름제어 객체)
- 서로 의존하면서, 변화를 감추면서 소프트웨어를 만들어야함
- 의존성 전이 : 의존하는 객체에게까지 변화를 끼침
- 변경 많은 것 = 구체적인 것 = 저수준 모듈은 의존 안하는 편이 -> 유지보수위해
- 캡슐화
- SRP : 객체가 단일책임
- ISP : 클라이언트마다 특화된 인터페이스 구현
=> 객체가 커지는것 막아줌
- OCP가 핵심!
- OCP를 할 수 있게 해주는 support 해주는 개념 : DIP, LSP
- DIP : 자주 변경되는 부분을 추상화하자
- LSP : 다형성을 이용하자
=> 기능확장 용이, 기존코드 변화는 적게
일기(회고)
- 지난주 목금 데브코스 방학이었는데
개인플젝 밀린 나는 방학을 가지지 못하고
게더를 들어갔는데 동지들이 있었다!- 고독한 코딩방을 함께했다(룰도 없음서 룰엄수하라며)
우리 뭔가 귀엽고 웃겨가지구 찍어놓음ㅋㅋㅋ - 아무도 안볼듯 하지만? 혹시나,,
본인의 이름을 지워달라 하는 분은 말해주실,,
- 고독한 코딩방을 함께했다(룰도 없음서 룰엄수하라며)
- 2주동안 과제랑 개인플젝이랑
정말 방학인줄알고 잡아둔 약속들 덕에
무리하다가 몸져 누웠다,,
세션듣다가 진짜 오한와서 덜덜 떨었다
공부도 좋지만 건강 최고!
- 개인플젝하면서 배운것들이나 에러는 따로 정리해야겠다
이미 오늘 TIL은 너무 뚱뚱쓰!
훈팀 테코톡은 하루에 하나씩 잘 듣고있고,
오늘부터 좀 무리해서 CS 하루에 하나씩 질문 정리하기로!
요것도 잘해보자~~
- 훈팀 미팅
- path vs query param : 도메인과 직접적으로 관련된 ID 같은 것들은 Path 파라미터로 처리하고 그외의 것들은 쿼리 파라미터로 사용하는 편
- Null 객체 패턴 : null 대신 빈 객체를 보내자
- 일급 컬렉션
- 중복 코드 방지
- 클래스를 한 번 더 Wrapping 한다고 생각하면 좋음