본문 바로가기

서버

JPA - 기본적인 어노테이션 간단히 살펴보기 (@ElementCollection, @FetchType.LAZY, EAGER, @EntityGraph, @GenereatedValue)

728x90

개요) 

JPA에서 기본적인 어노테이션을 살펴보자

 

1. @ElementCollection

2. @FetchType.LAZY,  @FetchType.EAGER

3. @EntityGraph

4. @GeneratedValue

 


[1. @ElementCollection]

 

이 어노테이션은

원하는 엔티티에서

칼럼 중 List를 넣고 싶을 때 사용한다

 

리스트 안에 요소는

Entity가 될 수 없다. 

 

RDB에서는

리스트 형식의 자료구조가 없기에

테이블로 따로 저장된다.

 

해당 테이블은

FK로 엔티티와 묶인다. 

 

아래 사진을 보자

 

 

UserRole은 

ENUM형태로 필드값이 들어가 있다. 

 

DB에는 어떻게 저장이 되는지 살펴보자

 

 

 

조회 했을 때

User 엔티티의 
UserRole이 리스트형태로 들어가 있다.

 

조회했을 때 쿼리문

 


[2. @FetchType.LAZY]

 

유저 엔티티 필드는 아래처럼 구성된다

 

[User.java]

package com.simple.project.domain;

import java.util.ArrayList;
import java.util.List;

import jakarta.persistence.Column;
import jakarta.persistence.ElementCollection;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Entity
@Table(name = "user")
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString(exclude = "userRoleList")
public class User {

 @Id
 @GeneratedValue(strategy = GenerationType.IDENTITY)
 @Column(name = "uno")
 private Long uno;

 private String userId;

 private String pw;

 @ElementCollection(fetch = FetchType.LAZY)
 @Builder.Default
 private List<UserRole> userRoleList = new ArrayList<>();

 public void addRole(UserRole userRole) {
  userRoleList.add(userRole);
 }

 public void clearRole() {
  userRoleList.clear();
 }

 public void changeUserId(String userId) {
  this.userId = userId;
 }

 public void changePw(String pw) {
  this.pw = pw;
 }

}

 

 

아래 소스는 

유저를 조회하는 조회문을 담당하는 메소드다

 

[UserRepository.java]

 

조회하면

아래의 쿼리로 조회된다.

 

 

User 엔티티의

UserRole은 왜 조회가 안될까? 

 

UserRole은

@ElementCollection으로 

외래키로 User테이블과 묶여 있지만

@FetchType.LAZY 으로 인해 

쿼리로 바로 수행되지 않는다.

 

해당 객체에 접근이 감지되면

쿼리수행이된다.

 

 

debug 상태에서

user 데이터를 살펴보려고 커서를 올려다 놓는 순간!

 

 

추가 조회 되는 걸 볼 수 있다. 

 

그렇다면 

@FetchType.EAGER로 테스트해보자! 

 


[3. @FetchType.EAGER]

 

 

유저 도메인에서

UserRole이 @ElementCollection으로 

외래키로 묶여있다.

 

해딩 필드값 속성이

@FetchType.LAZY 일 때는

 

UserRole 데이터에 접근될 때만 쿼리가 조회되었다.

Eager일 때는 어떨까?

 

[User.java]

package com.simple.project.domain;

import java.util.ArrayList;
import java.util.List;

import jakarta.persistence.Column;
import jakarta.persistence.ElementCollection;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Entity
@Table(name = "user")
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString(exclude = "userRoleList")
public class User {

 @Id
 @GeneratedValue(strategy = GenerationType.IDENTITY)
 @Column(name = "uno")
 private Long uno;

 private String userId;

 private String pw;

 @ElementCollection(fetch = FetchType.EAGER) //여기가 바뀜!
 @Builder.Default
 private List<UserRole> userRoleList = new ArrayList<>();

 public void addRole(UserRole userRole) {
  userRoleList.add(userRole);
 }

 public void clearRole() {
  userRoleList.clear();
 }

 public void changeUserId(String userId) {
  this.userId = userId;
 }

 public void changePw(String pw) {
  this.pw = pw;
 }

}

 

 

 

 

접근을 하든 안하든 

바로 쿼리가 실행되어 조회한다.

 

@FetchType.EAGER는 

@ElementCollection에 묶인 데이터에 접근 되든 안되든 바로조회!

 

@FetchType.LAZY는

@ElementCollection에 묶인 데이터에 접근 될 때만 조회!

 

음.. 

Join으로 쿼리 한번으로 조회 하려면 어떻게 해야할까?

 

그럴 땐 다음 방법으로 하면 된다!

 


 [4. @EntityGraph]

 

 

[UserRepository.java]

package com.simple.project.repository;

import java.util.Optional;

import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import com.simple.project.domain.User;

public interface UserRepository extends JpaRepository<User, Long> {
 @EntityGraph(attributePaths = { "userRoleList" })
 @Query("select u from User u where u.userId = :userId")
 Optional<User> getUser(@Param("userId") String userId);

}

 

 

JPARespository에서

@EntityGraph 의 속성값인 attributePaths에 

조인할 대상 테이블명을 넣어준다. 

 

조회할 원래 테이블인

"User" 안에 

attributePath의 대상테이블을 찾아

PK와 FK에 맞춰 Join 쿼리가 실행된다. 

 

결과를 비교해보자

@EntityGraph 적용 전과 후

 

@EntityGraph는

조인을 해주는데 

대상 테이블을 속성에 넣어줘야한다.


[4.@GeneratedValue]

 

@GeneratedValue는 기본 값이

Auto가 있고 IDENTITY가 있다. 

 

@GeneratedValue.IDENTITY는 

PK를 auto_increment로 

자동으로 생성해준다.