초급자를 위해 준비한
[백엔드, 웹 개발] 강의입니다.
JPA와 스프링 데이터 JPA의 기본 사용법을 알아봅니다.
✍️
이런 걸
배워요!
JPA 기본 매핑
스프링 데이터 JPA 기본 사용법
DB 연동의 열쇠 JPA!
실무 중심의 핵심 기본기를 빠르게 ????
백엔드 실무자를 위한
JPA & 스프링 데이터 JPA
인프런 강의
https://www.inflearn.com/course/jpa-spring-data-기초
유튜브
https://www.youtube.com/playlist?list=PLwouWTPuIjUi9Sih9mEci4Rqhz1VqiQXX
8.JPA 기초 08 값 콜렉션 Set 매핑











임베디드 타입
• 새로운 값 타입을 직접 정의할 수 있음
• JPA는 임베디드 타입(embedded type)이라 함
• 주로 기본 값 타입을 모아서 만들어서 복합 값 타입이라고도 함
• int, String과 같은 값 타입
임베디드 타입 사용법
• @Embeddable: 값 타입을 정의하는 곳에 표시
• @Embedded: 값 타입을 사용하는 곳에 표시
• 기본 생성자 필수
임베디드 타입의 장점
• 재사용
• 높은 응집도
• Period.isWork()처럼 해당 값 타입만 사용하는 의미 있는 메소드를 만들 수 있음
• 임베디드 타입을 포함한 모든 값 타입은, 값 타입을 소유한 엔티 티에 생명주기를 의존함
값 타입 컬렉션
• 값 타입을 하나 이상 저장할 때 사용
• @ElementCollection, @CollectionTable 사용
• 데이터베이스는 컬렉션을 같은 테이블에 저장할 수 없다.
• 컬렉션을 저장하기 위한 별도의 테이블이 필요함
값 타입 컬렉션 사용
• 값 타입 저장 예제
• 값 타입 조회 예제
• 값 타입 컬렉션도 지연 로딩 전략 사용
• 값 타입 수정 예제
• 참고: 값 타입 컬렉션은 영속성 전에(Cascade) + 고아 객체 제거 기능을 필수로 가진다고 볼 수 있다.
값 타입 컬렉션의 제약사항
• 값 타입은 엔티티와 다르게 식별자 개념이 없다.
• 값은 변경하면 추적이 어렵다.
• 값 타입 컬렉션에 변경 사항이 발생하면, 주인 엔티티와 연관된 모든 데이터를 삭제하고, 값 타입 컬렉션에 있는 현재 값을 모두 다시 저장한다.
• 값 타입 컬렉션을 매핑하는 테이블은 모든 컬럼을 묶어서 기본 키를 구성해야 함: null 입력X, 중복 저장X
값 타입 컬렉션 대안
• 실무에서는 상황에 따라 값 타입 컬렉션 대신에 일대다 관계를 고려
• 일대다 관계를 위한 엔티티를 만들고, 여기에서 값 타입을 사용
• 영속성 전이(Cascade) + 고아 객체 제거를 사용해서 값 타입 컬 렉션 처럼 사용
• EX) AddressEntity
정리
• 엔티티 타입의 특징
• 식별자O
• 생명 주기 관리
• 공유
• 값 타입의 특징
• 식별자X
• 생명 주기를 엔티티에 의존
• 공유하지 않는 것이 안전(복사해서 사용)
• 불변 객체로 만드는 것이 안전
항상 new 새롭게 생성하고, 수정시에는 기존것을 제거후 수정치한다.
Role
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Role {
@GeneratedValue(strategy = GenerationType.AUTO)
@Id
@Column
private Long id;
private String name;
/**
* 다음 코드로 role_perm 테이블이 생성되며
* 1.role_id 컬럼과 2."perm" 컬럼 이 생성된다.
*/
@ElementCollection
@CollectionTable(
name="role_perm", // role_perm 테이블 이름
joinColumns = @JoinColumn(name="role_id") //1.role_id 컬럼
)
@Column(name="perm") //2."perm" 컬럼
private Set<String> permissions=new HashSet<>();
public Role(String name, Set<String> permissions) {
this.name = name;
this.permissions=permissions;
}
}
RoleRepository
import org.springframework.data.jpa.repository.JpaRepository;
import study.datajpa.entity.Role;
public interface RoleRepository extends JpaRepository<Role, Long> {
public Role findByName(String name);
}
RoleTest
package study.datajpa.entity;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Rollback;
import org.springframework.transaction.annotation.Transactional;
import study.datajpa.repository.RoleRepository;
import javax.persistence.EntityManager;
import java.util.Set;
@SpringBootTest
@Transactional
@Rollback(value = false)
class RoleTest {
@Autowired
RoleRepository roleRepository;
@Autowired
EntityManager em;
@Test
public void 데이터등록() throws Throwable {
Role role1=new Role("ADMIN" , Set.of("F1", "F2"));
roleRepository.save(role1);
Role role2=new Role("GENERAL", Set.of("F3", "F4"));
roleRepository.save(role2);
roleRepository.findByName("ADMIN");
Role admin = roleRepository.findByName("ADMIN");
System.out.println("roleName = " + admin.getPermissions());
}
}
/* insert collection row study.datajpa.entity.Role.permissions */ insert into role_perm (role_id, perm) values (?, ?) /* insert collection row study.datajpa.entity.Role.permissions */ insert into role_perm (role_id, perm) values (1, 'F1');
9.JPA 기초 08 값 콜렉션 Set 매핑







Choice 객체 생성 후 @Embeddable


10.JPA 기초 08 값 콜렉션 Set 매핑







11.JPA 기초 11 값 콜렉션 주의사항





참고: 값 타입은 변경 불가능하게 설계해야 한다.
> @Setter 를 제거하고, 생성자에서 값을 모두 초기화해서 변경 불가능한 클래스를 만들자. JPA 스펙상 엔티티나 임베디드 타입( @Embeddable )은 자바 기본 생성자(default constructor)를 public 또는 protected 로 설정해야 한다. public 으로 두는 것 보다는 protected 로 설정하는 것이 그나마 더 안전하다.
> JPA가 이런 제약을 두는 이유는 JPA 구현 라이브러리가 객체를 생성할 때 리플랙션 같은 기술을 사용할 수 있도록 지원해야 하기 때문이다.
참조 : https://macaronics.net/index.php/m01/spring/view/2055
다대일 엔티에서 상관이 없으나 일대 다 엔티인 컬렉션에 문제가 발생한다.
1.지연 전략을 사용한다.
2. DISTINCT는 중복된 결과를 제거하는 명령을 사용한다.
3. 페치 조인을 사용해서 데이터를 가져오면 되지만. 페이징 처리에서 페이징 API(setFirstResult, setMaxResults)를 사용할 수 없다.
해결 방법:
페치 조인을 풀고, _batch_fetch_siz 전략을 통해 데이트를 가져온다.
#spring.jpa.properties.hibernate.default_batch_fetch_size=100
참조:
https://macaronics.net/index.php/m01/spring/view/2054
12.JPA 기초 12 영속 컨텍스트 & 라이프사이클






13.JPA 기초 13 엔티티 연관 매핑 시작에 앞서



14.JPA 기초 14 엔티티 간 1-1 단방향 연관 매핑
항상 지연로딩 fetch = FetchType.LAZY 을 사용해라


참조키 방식 1-1 단방향 연관 매핑



식별자 공유 방식 1-1 단방향 연관 매핑



15.JPA 기초 15 엔티티 간 N-1 단방향 연관 매핑
항상 지연로딩 fetch = FetchType.LAZY 을 사용해라






16.JPA 기초 16 엔티티 간 1-N 단방향 연관 매핑














17.JPA 기초 17 영속성 전파 & 연관 고려사항






















댓글 ( 4)
댓글 남기기