JPA 15

JPA MultipleBagFetchException에러 해결하기

개요 동아리 프로젝트에서 Stylist의 정보를 모든 조회하기 위해 Fetch조인을 사용하는 과정에서 JPA의 N + 1문제를 해결하기 위해 Left Join Fetch을 사용하여 해결하려고 했지만 MultipleBagFetchException이 발생했다. 이유를 알아보자 상황 일단 Stylist의 관계를 알아보자 Stylist는 0~3개의 Career를 가질 수 있다. Stylist는 0~3개의 Style을 등록할 수 있다. Stylist는 0~5개의 StylistService를 등록할 수 있다. StylistService는 0~2개의 ServiceCategory를 등록할 수 있다. 즉 Stylist에 OneToMany로 연결되어있다. public class Stylist implements UserD..

JPA 2024.01.20

JPQL(Java Persistence Query Language)

jpa는 다양한 쿼리 방법을 지원한다 1. jpql 2. jpa criteria 3. queryDSL 4. 네이티브 SQL 5. JDBC API 직접 사용, MyBatis, SpringJdbcTemplate함께 사용 jpql = 동적 쿼리 힘들다. 실무에서 문자열 +힘들다 criteria = sql 스럽지 않다, 유지보수 어렵다. JPQL JPQL은 객체지향 쿼리 언어다. 따라서 테이블을 대상으로 쿼리를 작성하는 것이 아니라 엔티티 객체를 대상으로 쿼리를 작성한다. JPQL은 SQL을 추상화해서 특정데이터베이스 SQL에 의존하지 않는다. JPQL은 결국 SQL로 변환된다.(매핑 정보와 방언을 조합해서) JPQL 문법 엔티티와 속성은 대소문자 구분한다.(Member) JPQL 키워드는 대소문자 구분을 하지..

JPA 2024.01.03

값 타입, 값 타입 컬렉션

값 타입 공유 참조 임베디드 타입 같은 값 타입을 여러 엔티티에서 공유하면 위험하다 부작용이 발생한다. 회원1, 회원2가 같은 주소의 타입을 공유하고 있을 때 그 값으로 OldCity가지고 있었는데 city값을 NewCity로 변경하면 회원1, 회원2가 가지고 있는 주소의 값이 변경될 수 있다. 코드를 살펴보자 Address address = new Address("city" , "street", "10000"); Member member1 = new Member(); member1.setName("member1"); member1.setHomeAddress(address); em.persist(member1); Member member2 = new Member(); member2.setName("mem..

JPA 2023.09.01

임베디드 타입

임베디드 타입 새로운 값 타입을 직접 정의할 수 있음 JPA는 임베디드(embedded type) 타입이라 함 주로 기본 값 타입을 모아서 만들어서 복합 값 타입이라고도 함 int, String과 같은 특성의 값 타입 엔티티가 아니어서 변경하면 추적이 안된다 위와 같은 회원 엔티티가 있다고 보자 회원 엔티티의 필드를 보면 (startDate, endDate) = workPeriod, (city, street, zipcode) = homeAddress필드를 묶을 수 있다. 이렇게 묶을 수 있는 것이 임베디드 타입이다. Period, Address를 클래스를 만들어서 저장하면 된다. 임베디드 타입 사용법 @Embeddable : 값 타입을 정의하는 곳에 표시 @Embedded : 값 타입을 사용하는 곳에 표..

JPA 2023.08.31

기본값 타입

JPA는 데이터 타입을 2가지로 분류한다. 엔티티 타입 @Entity로 정의하는 객체 데이터가 변해도 식별자로 지속해서 추적가능 예) 회원 엔티티의 키나 나이 값을 변경해도 식별자(Id)는 유지되기 때문에 인식 가능 값 타입 int, Integer, String처럼 단순히 값으로 사용하는 자바 기본 타입이나 객체 식별자(id)가 없고 값만 있으므로 변경 시 추적 불가능 예) 숫자 100을 200으로 변경하면 완전히 다른 값으로 대체 값 타입 기본값 타입 자바 기본 타입(int, double) 래퍼 클래스 (Integer, Long) String 임베디드 타입 컬렉션 값 타입 기본값 타입 예) String name, int age 생명주기를 엔티티에 의존 예) 회원 엔티티를 삭제하면 이름, 나이 필드도 같..

JPA 2023.08.31

영속성 전이 : CASCADE, 고아객체

특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 만들고 싶을 때 예) 부모 엔티티를 저장할 때 자식 엔티티도 함께 저장 (persist) Parent와 Child 코드를 보자 @Entity public class Parent { @Id @GeneratedValue private Long id; private String name; @OneToMany(mappedBy = "parent") private List childList = new ArrayList(); public void addChild(Child child) { child.setParent(this); childList.add(child); } @Entity public class Child { @Id @Generated..

JPA 2023.08.31

즉시 로딩과 지연 로딩

Member와 Team이 [N : 1] 연관 관계 매핑이 되어있는 상태에서 Member를 조회할 때 상항 Team을 같이 조회해야 할까? 비즈니스 로직이 단순 Member정보만 사용하는 경우에 Team 테이블도 Join해서 데이터를 가져오면 손해가 발생된다. LAZY을 사용하여 지연 로딩을 해보자 @Entity public class Member extends BaseEntity{ @Id @GeneratedValue @Column(name = "MEMBER_ID") private Long id; @Column(name = "USERNAME") private String name; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "TEAM_ID") priva..

JPA 2023.08.30

프록시와 연관관계 관리

Member와 Team이 연관관계로 매핑이 되어있는 상황을 예시로 생각해 보자 비즈니스 로직에 따라 Member를 조회하고 자주 Team을 찾는 경우, Member만 사용을 많이 하는 경우가 있다. 각 경우에 따라 전자는 Team까지 같이 가져오는 SQL을 하는 것이 후자는 Member만 가져오는 SQL을 작성하는 것이 유리하다. 이를 해결하지위해 JPA는 지연로딩과 프록시를 사용한다. 프록시 em.find() vs em.getReference() em.find : 데이터베이스를 통해서 실제 엔티티 객체를 조회 Member와 Team 테이블을 Join해서 가져온다 em.getReference() : 데이터베이스 조회를 미루는 가짜(프락시) 엔티티 객체 조회 getReference하는 시점에는 DB에 쿼리..

JPA 2023.08.30

MappedSuperclass

MappedSuperclass의 사용을 아래의 예시를 통해 알아보자 객체의 입장에서 id, name의 필드가 계속 나올 때 BaseEntity에 속성만 두고 상속해서 사용할 때 사용한다 DB는 각각 따로 사용한다. 이렇게 공통매핑 정보가 필요할 때 사용한다. 다른 예시를 보자 만약 Team과 Member 클래스의 공통 정보 필드가 아래와 같이 있다고 보자 private String createdBy; private LocalDateTime createDate; private String lastModifiedBy; private LocalDateTime lastModifiedDate; 공통 정보를 처리하기 위해 BaseEntity라는 클래스를 만들자 @MappedSuperclass public abstr..

JPA 2023.08.30

상속관계 매핑

관계형 데이터베이스에는 상속 관계가 없다. 슈퍼타입 서브타입 관계라는 모델링 기법이 객체 상속과 유사하다. 상속관계 매핑 : 객체의 상속과 구조의 DB의 슈퍼타입 서브타입관계를 매핑 상속관계 매핑 슈퍼타입 서브타입 논리 모델을 실제 물리 모델로 구현하는 방법 각각 테이블로 변환 -> 조인 전략 통합 테이블로 변환 -> 단일 테이블 전략 서브타입 테이블로 변환 ->구현 클래스마다 테이블 전략 위 3개의 방법 어느 것을 사용하더라도 JPA에서는 매핑이 가능하다. 각 Entity를 만들어 보자 @Entity public class Item { @Id @GeneratedValue private Long id; private String name; private int price; } @Entity public ..

JPA 2023.08.29