초급자를 위해 준비한
[백엔드, 웹 개발] 강의입니다.
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)
댓글 남기기