Entity를 Controller까지 그대로 노출 할때 발생할 수 있는 문제점

2026. 3. 9. 13:41·코드잇 스프린트/실습

1. Entity와 API의 강한 결합이 생긴다.

Entity를 그대로 반환하면 API 응답 구조가 Entity 구조와 동일해진다.

이렇게 되면 Entity 구조가 바뀌면, API 도 같이 바뀌어야한다.

 

DTO를 사용하면

  • Entity(DB 모델)
  • DTO(API 모델)

로 분리할 수 있다.


2. OSIV = false 환경에서 Lazy Loading 문제

 

OSIV(Open Session In View)가 무엇인가?

OSIV는 Hibernate Session(영속성 컨텍스트)를 어디까지 유지할지 결저하는 설정

spring.jpa.open-in-view=false

OSIV = true(기본값) : Controller 까지 영속성 컨텍스트 유지

OSIV = false: Service 트랜잭션이 끝나면 영속성 컨텍스트 종료

실제 서비스에서는 성능과 DB 커넥션 관리때문에 OSIV를 false로 두는 경우가 많다.

 

영속성 컨텍스트는 Entity를 관리하는 JPA 메모리 공간이다. 여기 안에 있는 Entity는 DB와 연결된 상태라서

Lazy Loading,Dirty Checking(변경 탐지) 같은 기능이 동작한다.

 

OSIV = true이면 HTTP 요청 시작 -> 영속성 컨텍스트 생성 -> Controller -> Service -> Repository-> Controller응답

-> 영속성 컨텍스트 종료

즉, Controller에서도 Entity가 관리 상태이다. 그래서 Lazy Loading이 Controller에서도 된다.

 

OSIV = false이면 Service -> 영속성 컨텍스트 종료라서 Controller 단에서 조회할경우 영속성 컨텍스트 없음/DB 연결 없음으로 인해 LazyInitializationException이 발생한다.

 

이는, Entity를 반환할 경우 .....

따라서 DTO를 사용하면 이런 문제를 해결한다.

 


 

3. 양방향 연관관계에서 순환 참조 문제

Entity에 양방향 관계가 있으면 JSON 직렬화시 무한 루프가 발생할 수 있다.

 

class Channel {
    @OneToMany
    List<Message> messages;
}

class Message {
    @ManyToOne
    Channel channel;
}

서로가 서로를 참조하는 구조이다. (양방향 연관관계)

 

@GetMapping("/channels/{id}")
public Channel getChannel(@PathVariable UUID id) {
    return channelService.find(id);
}

Channel을 직렬화 한다고 했을때 Channel내 message가 List이므로 JSON 형태로 직렬화한다.

message에는 channel이 또 있다. 다시 Channel을 직렬화 한다. 이 구조가 무한 반복된다.

Channel
 → Message
   → Channel
     → Message
       → Channel

결과적으로 StackOverflowError가 생긴다.

DTO를 사용하면 필요한 데이터만 선택적으로 반환할 수 있다.

 

DTO를 사용하면 

class MessageDto {
    String content;
    UUID channelId;
}
{
  "content": "hello",
  "channelId": "1234"
}

이런식으로 필요한 데이터만 선택적으로 반환할 수 있어서 순환 구조가 존재하지 않는다.


4.민감한 데이터 노출 위험

Entity에는 외부에 노출하면 안되는 데이터가 포함될 수 있다.

@Entity
class User {
    String email;
    String password;
    String refreshToken;
}

이 Entity를 그대로 반환하면 password와 토큰이 노출되는 보안문제가 발생 할 수 있다.


5. DTO 사용시 보일러 플레이트 코드 증가

@GetMapping("/messages/{id}")
public Message find(@PathVariable UUID id) {
    return messageService.find(id);
}
public Message find(UUID id) {
    return messageRepository.findById(id).orElseThrow();
}

이런식으로 Entity를 그대로 반환한다고 하면 추가 코드가 거의 없다.

 

DTO를 사용하게 되면

  • DTO 클래스를 따로 만들어야한다.
  • Entity를 DTO로 변환하는 코드가 필요하다.
  • 그래서 코드가 늘어난다.

이런걸 반복적으로 작성해야하는 코드를 "보일러플레이트 코드" 라고 한다.


[그래도 DTO를 사용하는 이유]

API와 DB 구조 분리
민감 데이터 보호
순환 참조 방지
Lazy Loading 문제 방지

 

'코드잇 스프린트 > 실습' 카테고리의 다른 글

BinaryContent 저장로직 고도화  (0) 2026.03.09
MapStruct 라이브러리를 통해 Entity를 DTO로 자동 변환  (0) 2026.03.09
디스코드 프로젝트 실습: Entity 정의하기(JPA 어노테이션,cascade,고아객체)  (0) 2026.03.05
JPA사용 직접 작성한 DDL로 테이블 생성(schema.sql)  (0) 2026.03.04
JPA ERROR : user는 PostgreSQL 예약어라서 테이블명을 따로 정해야한다.  (0) 2026.03.03
'코드잇 스프린트/실습' 카테고리의 다른 글
  • BinaryContent 저장로직 고도화
  • MapStruct 라이브러리를 통해 Entity를 DTO로 자동 변환
  • 디스코드 프로젝트 실습: Entity 정의하기(JPA 어노테이션,cascade,고아객체)
  • JPA사용 직접 작성한 DDL로 테이블 생성(schema.sql)
과컴
과컴
벡엔드 개발자 최소기준 맞추겠습니다.
  • 과컴
    곽의 프로그램
    과컴
  • 전체
    오늘
    어제
    • 분류 전체보기 (76)
      • 위클리페이퍼 (6)
      • 파이썬 (4)
      • 코드잇 스프린트 (48)
        • Spring 이론 (7)
        • Java이론 (11)
        • 실습 (23)
      • 백엔드 개발자 최소기준 (1)
      • 코딩테스트 (5)
        • 알고리즘 (0)
        • SQL (1)
      • Git (5)
      • 스프링부트 핵심가이드 (1)
      • 트러블 슈팅 (2)
  • 블로그 메뉴

    • 홈
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    파이썬
    백준2576
    파이썬기초
    백준브론즈
    혼공파
    파이썬입문
    백준1152
    문자열
    백준1075번
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
과컴
Entity를 Controller까지 그대로 노출 할때 발생할 수 있는 문제점
상단으로

티스토리툴바