spring jpa

2024. 5. 20. 17:36카테고리 없음

오늘 공부한 내용 정리

@Column -> 엔티티 필드명은 name인데 참조하는 테이블의 필드명은 user_name 일때 매핑할 수 있음. 제약조건을 걸 수 있음

@JoinColumn -> 연관관계 매핑시에 사용됨.(해당 필드가 외래키가 됨)

@OneToMany(mappedBy = "") -> 양방향 관계일때 누가 외래키를 가져야하는지 정해야함. mappedBy를 통해 자신이 연관관계의 주인이 아닌 것을 표시. mappedBy에는 어떤 필드가 외래키를 가졌는지 명시해줘야함.

 

@Embedded , @Embedding -> VO를 만들고 entity 필드로 선언할때 이게 값타입임을 명시하기 위해 사용. VO에 선언된 필드들이 테이블에 그대로 적힘.

 

@Enumerated(value = EnumType.STRING) : Enum은 순서대로 0, 1 ,2 이렇게 기본으로 저장되는데 중간에 한가지를 추가하면 순서가 밀려서 의도치 않은 결과가 나온다. 이를 방지하기위해 string으로 저장하는 옵션 

 

일대다 다대일 헷갈릴때

유저 (다 대 일) 팀

여러명의 유저는 한 팀일수있음

유저에서 팀 (many to one)

팀에서 유저 (one to many)

일의 입장에서 다를 관리해야하니 배열로 관리

다의 입장에선 연결관계만 알면되니 단일로 관리


연관관계에서 단방향이든 양방향이든 다대일은 일단 다쪽에서 외래키를 관리함. 일대일에서는 수정사항이 많은 쪽이 외래키를 관리하는게 유리함. 외래키가 있는 연관관계의 주인에서만 변경사항이 저장됨.

 

연관관계에서의 삭제 (외래키를 가진쪽(다, 연관관계의 주인, 자식)이 자식, 가지지 않은 쪽(일)이 부모)

외래키를 가진(자식)쪽의 데이터를 삭제하는건 문제가 안되지만 외래키를 가지지 않은 쪽의 데이터를 삭제하면 자식이 참조하고 있는

데이터가 없어지니까 문제가 됨. 그래서 그냥 삭제하면 오류 발생하고 위의  OnDeleteAction.CASCADE 이나 CascadeType.REMOVE 로 부모를 삭제할때 자식도 삭제되도록 만들거나 자식의 외래키의 Null 옵션을 허용해서 외래키를 Null로 만들어주고 삭제해야함.

 

다대일 단방향 관계에선 일(부모)은 다(자식)에 대해 아무것도 모른다. 일을 삭제했을 때 양방향 관계라면 스프링이 일을 통해 부모로 가서 자식을 삭제해줄 수 있는데 단방향이기 때문에 일을 통해 부모로 갈 수가 없다. 이때 OnDeleteAction.CASCADE 와 CascadeType.REMOVE의 차이가 나타난다.(DB에서 외래키 무결성을 관리하도록 설정하고 싶다면 OnDeleteAction.CASCADE 다대일 단방향 관계의 상황에선 OnDeleteAction.CASCADE 로 DB가 자식을 삭제하도록 설정할 수 있다.)

ht

 

[ElectionPJT/JPA] JPA의 외래 키 무결성 / Candidate Entity에서 양방향 매핑을 포기한 이유

JPA에서 외래 키 무결성을 다루는 방법

velog.io

 

 

외래키

-> 무결성을위해 설정

-> db에 따라 자동 인덱싱

-> 생성 순서에 영향을 주기 때문에 테스트코드 작성이 어렵고 개발 편의가 중요하다면 인덱스만 쓰고 무결성을 포기하는 선택도 함

-> null 을 허용하여 자식의 참조를 제거하는 선택을 할 수 있음.

 

인덱스

-> where로 인덱스 설정한 열을 대상으로 조건을 걸 때 사용됨

-> 설정한 열은 중복이 없을수록 좋음

-> 데이터 변경이 자주일어나는 경우 비용이 늘어나니 그런 

-> 모든 데이터만 조회하는 경우 사용안함 

 

[MySQL] - 인덱스 (INDEX) 정리 (동작 방식, 생성, 삭제, 설계)

인덱스란? 인덱스는 데이터베이스에서 데이터를 조회할 때 결과를 빠르게 추출하도록 도와주는 하나의 '데이터베이스 개체'입니다. 마치 사전의 '찾아보기'와 같은 역할을 한다고 생각하시면

rachel0115.tistory.com

 

연관관계 엔티티 조회

조인, 패치조인

fetch join은 하나의 쿼리로 연관 엔티티까지 모두 불러오고

 join은 일단 검색 엔티티 부르고 연관 엔티티 개수 만큼 쿼리를 따로 날러 불러옴.

 

em.find

데이터가 한번에 불러져야하는데 jpql로 그냥 select 하거나 select join 하면

연관 엔티티 개수만큼 추가 sql이 생성됨.

좌: select e from Employee e , 우: select e from Employee e join e.department

-> A,B가 연관관계를 가질때 A를 검색하면 일반 조인은 inner join으로 A에 열만 조회하고 연관 엔티티는 따로 쿼리를 날리는데 패치조인은 A와B의 모든 열을 조회.

! 단 패치조인 할때 2개 이상의 컬랙션 존재하면 안됨

 

N+1 문제

위처럼 select나 join 할때 연관 엔티티 개수만큼 쿼리가 n개 만큼 더 날라가는 문제

지연 로딩으로 이 문제를 완화 시킬 수 있음. 지연로딩 설정하면 실제 연관 엔티티를 쓸때 쿼리가 날라감.

하지만 연관 엔티티를 모두 조회하면 결국 n+1 번의 쿼리가 실행되는건 똑같음.

 

여기서 select d.name from Employee e join e.department d 만 하면 일반 조인을 하더라도 n+1 문제가 안일어남.

 

일반 조인으로 연관쿼리의 필드를 불러오는 jpql 쿼리를 작성한다면 n+1문제가 일어나지않음.

 

 

 

[JPA] @ManyToOne 연관 관계와 Select 쿼리

JPA의 @ManyToOne JPA에서 엔티티 간의 다대일(N : 1) 연관 관계를 설정하기 위해서는 @ManyToOne 어노테이션을 사용하는데, 이 설정의 기본 페치 전략은 EAGER 즉, 즉시 로딩 전략으로 설정되어 있다. /** * (

developer-youngjun.tistory.com

 

 

연관관계(em.find , jpql) select test

 

[JPA] @ManyToOne 연관 관계와 Select 쿼리

JPA의 @ManyToOne JPA에서 엔티티 간의 다대일(N : 1) 연관 관계를 설정하기 위해서는 @ManyToOne 어노테이션을 사용하는데, 이 설정의 기본 페치 전략은 EAGER 즉, 즉시 로딩 전략으로 설정되어 있다. /** * (

developer-youngjun.tistory.com

 

엔티티 그대로 반환하는게 아닌 특정 열들을 조회하는 경우

List<Object[]> results = em.createQuery("SELECT w.nickname, b.id, b.content FROM Board b JOIN b.writer w").getResultList();

for (Object[] result : results) {
    String writerNickname = (String) result[0];
    Long boardId = (Long) result[1];
    String boardContent = (String) result[2];

    System.out.println("Writer Nickname: " + writerNickname);
    System.out.println("Board ID: " + boardId);
    System.out.println("Board Content: " + boardContent);
}

 

List<Object>를 통해 반환됨.

jpql 의 순서대로 들어감. 만약 b.id, n.content 대신 b 를 넣으면 result[1]은 (Board)를 해야함.

 

엔티티 수정

 

JPA 영속성관리 공부의 기록

공부의 기록 시리즈는 공유하고자 적는 글이 아닙니다. 공부할때 필기 하는 습관이 있고, 모르는 내용을 메모할 공간이 필요하기 때문에 적는 글입니다. 나중에 이 글을 잘 정제하고 편집해서

velog.io

 

영속? 비영속? 준영속?

영속은 em.persist로 영속성 컨택스트로 관리되는 상태

비영속과 준영속 차이는 id의 여부인데 jpa는 Id가 있으면 이미 영속상태였다가 빠져나온 준영속 상태로 인식한다

 

영속 -> 준영속

em.detach

 

영속 -> 비영속

em.remove

 

db -> 영속

em.find

 

비영속 -> 영속

em.persist

 

수정같은 경우는 변경감지와 병합이 있다.

변경감지는 영속상태에서 그냥 변경하면 초기 상태와 비교에 알아서 db에 저장해주는 것.

병합은 준영속 상태에 객체를 em.merge 하면 기존의 객체에 덮어 씌우는 것이다.

 

병합시 필드의 값이 없다면 null인 상태로 덮어씌워진다.