유쨈미 2024. 7. 24. 18:08

1. @PostConstruct

@PostConstruct는 Java EE와 Spring Framework에서 사용되는 어노테이션으로, 빈의 생성과 의존성 주입이
완료된 후 실행되어야 하는 메소드를 지정한다. 이 어노테이션이 붙은 메소드는 객체 생성 후 자동으로 호출되어
초기화 작업을 수행한다.

 

💡 주요 특징

  1. 의존성 주입 완료 후 실행
  2. 클래스당 한 번만 호출
  3. 트랜잭션 처리 불가

 

📌 속성과 설명

메소드/속성 설명
@PostConstruct 초기화 메소드 지정

 

💻 예시 코드

@Component
public class MyService {
    private final DatabaseClient databaseClient;

    @Autowired
    public MyService(DatabaseClient databaseClient) {
        this.databaseClient = databaseClient;
    }

    @PostConstruct
    public void init() {
        databaseClient.connect();
        System.out.println("Database connection initialized");
    }
}
 

Spring Boot에서 @PostConstruct 알아보자!

spring boot : 2.6.1의존성 주입이 완료된 후에 실행되어야 하는 method에 사용해당 어노테이션은 다른 리소스에서 호출되지 않아도 수행생성자 보다 늦게 호출된다.호출 순서생성자 호출의존성 주입

velog.io

- 참고 : Karim.log


2. @Temporal(TemporalType.DATE) : JPA에서 사용

@Temporal은 JPA에서 날짜 타입 (java.util.Date, java.util.Calendar)을 매핑할 때 사용하는 어노테이션이다.
TemporalType.DATE는 날짜 정보만 데이터베이스에 저장함을 지정한다.

 

📌 속성과 설명

속성 설명
TemporalType.DATE 날짜만 저장
TemporalType.TIME 시간만 저장
TemporalType.TIMESTAMP 날짜와 시간 모두 저장

 

💻 예시 코드

@Entity
public class Event {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Temporal(TemporalType.DATE)
    private Date eventDate;

    // getters and setters
}
 

[JPA] 엔티티 매핑 - @Temporal, @Enumerated, @Lob, @Transient

[JPA] 엔티티 매핑 - @Entity, @Table, @Column 엔티티매니저에 의해 생성된 엔티티는 DB의 테이블과 매핑된다. 매핑 작업은 JPA프레임워크가 담당한다. 개발자가 해야할 일은 어떤 엔티티가 어떤 테이블

lordofkangs.tistory.com

- 참고 : lordofkangs


3. Fech Join

Fetch Join은 JPA에서 연관된 엔티티나 컬렉션을 한 번의 쿼리로 함께 조회하는 기능이다.
N+1 문제를 해결하고 성능을 최적화하는 데 사용된다.

 

💡 주요 특징

  1. 연관 엔티티를 즉시 로딩
  2. JPQL에서 'JOIN FETCH' 키워드 사용
  3. 페이징 처리에 제한이 있음

 

🚀 N+1문제란?

더보기

ORM(Object-Relational Mapping) 프레임워크를 사용할 때 자주 발생하는 성능 문제이다.
이 문제는 주로 연관된 엔티티를 조회할 때 발생하며, 데이터베이스 쿼리 수가 불필요하게 많아지는 현상을 말한다.

 

💡 N+1 문제의 원인

  1. 최초 쿼리로 N개의 엔티티를 조회
  2. 각 엔티티의 연관된 엔티티를 조회하기 위해 N번의 추가 쿼리 실행

 

결과적으로 1(최초 쿼리) + N(연관 엔티티 조회) 번의 쿼리가 실행된다.

 

💻 예시 상황 코드

@Entity
public class Post {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String title;

    @OneToMany(mappedBy = "post", fetch = FetchType.LAZY)
    private List<Comment> comments;
    
    // getters and setters
}

@Entity
public class Comment {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String content;

    @ManyToOne(fetch = FetchType.LAZY)
    private Post post;
    
    // getters and setters
}

 

 ❗ N+1 문제 발생 코드

List<Post> posts = postRepository.findAll();
for (Post post : posts) {
    System.out.println(post.getComments().size()); // 각 포스트의 댓글 수 출력
}

 

이 코드는 다음과 같은 쿼리를 실행한다.

  1. 모든 POST 조회 (1번의 쿼리)
  2. 각 POST의 Commit 조회 (N번의 쿼리)

 

 💡 N+1 문제의 해결 방법

 

1️⃣ Fetch Join 사용 

@Query("SELECT p FROM Post p JOIN FETCH p.comments")
List<Post> findAllWithComments();

 

 2️⃣ EntityGraph 사용

@EntityGraph(attributePaths = {"comments"})
List<Post> findAll();

 

 3️⃣ BatchSize 설정

@Entity
public class Post {
    // ...
    @OneToMany(mappedBy = "post", fetch = FetchType.LAZY)
    @BatchSize(size = 100)
    private List<Comment> comments;
    // ...
}

 

 4️⃣ @Fetch (FetchMode.SUBSELECT) 사용

@Entity
public class Post {
    // ...
    @OneToMany(mappedBy = "post", fetch = FetchType.LAZY)
    @Fetch(FetchMode.SUBSELECT)
    private List<Comment> comments;
    // ...
}

 

5️⃣ DTO 프로젝션 사용

@Query("SELECT new com.example.PostDTO(p.id, p.title, SIZE(p.comments)) FROM Post p")
List<PostDTO> findAllPostsWithCommentCount();

 

 📌 각 해결 방법의 장단점

해결 방법 장점 단점
Fetch Join 한 번의 쿼리로 모든 데이터 조회 카테시안 곱으로 인한 데이터 중복, 페이징 불가
EntityGraph 유연한 설정 가능 복잡한 관계에서 사용이 어려움
BatchSize 여러 쿼리를 하나로 묶음 최적의 사이즈 설정 필요
SUBSELECT  컬렉션 조회 시 효율적 항상 서브쿼리 사용으로 인한 성능 저하 가능
DTO 프로젝션 필요한 데이터만 정확히 조 추가 매핑 작업 필요

 

🚀 Fetch Type이란?

JPA에서 연관 엔티티를 불러오는 시점을 결정하는 속성이다. 주로 @OneToMany, @ManyToOne 등의 연관관계 매핑 어노테이션과 함께 사용되며, 성능과 데이터 일관성에 중요한 영향을 미친다.

 

💡 JPA에서 제공하는 두 가지 Fetch Type

Fetch Type 설명 장점 단점
EAGER 연관 엔티티를
즉시 함께 조회
연관 데이터를
항상 사용할 때 유용
불필요한 데이터도
항상 조회하여 성능 저하 가능
LAZY 연관 엔티티를
실제 사용 시점에 조회
필요 시점에만 데이터 로드하여
성능 향상
N+1 문제 발생 가능,
세션 종료 후 사용 시 문제 발생

 

💻 예시 코드

@Entity
public class Post {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String title;

    @OneToMany(mappedBy = "post", fetch = FetchType.LAZY)
    private List<Comment> comments;
    
    // getters and setters
}

@Entity
public class Comment {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String content;

    @ManyToOne(fetch = FetchType.EAGER)
    private Post post;
    
    // getters and setters
}

 

📌 Fetch Type 사용 시 주의사항

  1. @OneToMany, @ManyToMany
    기본 값이 LAZY

  2. @OneToOne, @ManyToOne
    기본 값이 EAGER

 

💡 Fetch Type 선택 기준

  1. 연관 엔티티를 자주 사용하는 경우 → EAGER 고려
  2. 연관 엔티티를 가끔 사용하는 경우 → LAZY 사용
  3. 성능 최적화가 필요한 경우 → 상황에 따라 동적으로 결정 (JPQL의 Fetch Join 등 활용)

 

 

페치 조인

페치 조인(fetch join) 페치 조인이란 SQL 조인의 종류가 아니며, JPQL에서 성능 최적화를 위해서 제공해주는 기능이다. 페치 조인은 엔티티를 조회할 때 연관된 엔티티나 컬렉션을 한 번의 SQL로 함께

kimtaesoo99.tistory.com

-참고 : kimtaesoo99

 

[Spring] 패치조인(fetch Join)이란?

ㅁ 들어가며ㅇ [Spring] JDBC와 MyBatis와 JPA 비교, 시대적 흐름에서 장단점 분석에서 JDBC, MyBatis, JPA의 시대적 흐름에 따른 장단점을 정리하였다.ㅇ JPA의 장단점을 요약적으로 정리하고 fetch Join이 왜

peterica.tistory.com

- 참고 : peterica

 

[JPA] 일반 Join과 Fetch Join의 차이

JPA를 사용하다 보면 바로 N+1의 문제에 마주치고 바로 Fetch Join을 접하게 됩니다. 처음 Fetch Join을 접했을 때 왜 일반 Join으로 해결하면 안되는지에 대해 명확히 정리가 안된 채로 Fetch Join을 사용했

cobbybb.tistory.com

- 참고 : cobbybb

 

[JPA] Fetch - Eager, Lazy

Fetch란? Fetch의 사전적 의미는 '(어디를 가서) ~을 가지고 오다' 라는 뜻이다. JPA에서도 이 의미는 일맥상통한다. JPA에서 Fetch는 엔티티의 필드에 DB에서 실제 값을 가져오는 것이고 가져오는 방법

somuchthings.tistory.com

- 참고 : somuchthings

 

JPA의 LazyInitializationException

JPA를 사용하는 경우 잊을 만하면 만나는 LazyInitializationException 을 해결 하는 방법 정리

velog.io

- 참고 : iamcoder.log


4. Entity DTO 분리, 차이점

Entity는 데이터베이스 테이블과 매핑되는 객체이고, DTO는 계층 간 데이터 전송을 위한 객체이다.
이들을 분리하여 사용하면 각 객체의 책임을 명확히 하고, 데이터베이스 구조 변경의 영향을 최소화할 수 있다.

 

📌 주요 차이점

특성 Entity DTO
목적 데이터베이스 매핑 데이터 전송
영속성 JPA 관리 일반 Java 객체
변경 신중히 다룸 자유롭게 변경 가능

 

💻 예시 코드

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String password;
    // getters and setters
}

public class UserDTO {
    private String username;
    // getter and setter
}
 

📚 Dto와 Entity를 분리하는 이유, 분리하는 방법

작년에 프로젝트를 하면서 entity를 view에 그대로 반환했다가 Dto로 변환해야겠다는 생각이 들어서 바꿨었는데, Entity와 dto에 대한 내용을 블로그에 정리하면 좋을 거 같아 글을 쓰게 되었다. (일기

velog.io

- 참고 : 0sunset0.log

 

역할 분리를 위한 Entity, DTO 개념과 차이점

'Entity, DTO 개념과 차이점 (+ VO)' - Entity Entity 클래스는 실제 DB 테이블과 매핑되는 핵심 클래스로, 데이터베이스의 테이블에 존재하는 컬럼들을 필드로 가지는 객체입니다. (DB의 테이블과 1:1로 매

wildeveloperetrain.tistory.com

- 참고 : wildeveloperetrain

 

Entity와 DTO 분리

* Entity와 DTO 분리 *Entity는 데이터베이스와 연관이 있으며 데이터베이스의 영속성을 관리하기 위한 역할을 한다. DTO는 클라이언트와 서버 간의 데이터 전송을 관리하고, 필요한 데이터를 포함하

cafe.daum.net

- 출처 : 데이터 과학자 + 프로그래머 세상 다음카페


5. Spring Model

Spring Model은 컨트롤러에서 뷰로 데이터를 전달하는 데 사용되는 인터페이스이다.
주로 뷰에서 표시할 데이터를 담아 전달하는 역할을 한다.

 

💡 주요 메소드

메소드 설명
addAttribute(String name, Object value) 모델에 속성 추가
getAttribute(String name) 속성 값 조회
asMap() 모델의 모든 속성을 Map으로 반환

 

💻 예시 코드

@Controller
public class UserController {
    @GetMapping("/user/{id}")
    public String getUser(@PathVariable Long id, Model model) {
        User user = userService.findById(id);
        model.addAttribute("user", user);
        return "user-details";
    }
}
 

스프링에서 Model

Model은 어디서 오는?어디에서 만들어지는?생명주기는?사용 방법은?실생활에서도 자주 쓰여지는지?

velog.io

- 참고 : jungnoeun.log