개발을 하다 보면 한 가지 의문이 생긴다.
"Entity랑 DTO, 왜 굳이 나눠서 써야 하지?"
처음엔 둘 다 그냥 데이터를 담는 그릇처럼 보인다.
하지만, 이 두 객체는 그 목적과 사용되는 맥락이 다르기 때문에, 실제로는 각각 다른 역할을 수행한다.
이 글에서는 Entity와 DTO의 차이점을 명확히 구분하고, 왜 둘을 분리해서 사용하는 것이 중요한지에 대해 살펴보겠다.
1. Entity
"Entity는 데이터베이스 테이블과 1:1로 매핑되는 객체이다."
특징
- @Entity로 선언되고, 주로 JPA 같은 ORM과 함께 사용된다.
- DB에 직접 저장하거나 조회하는 객체다.
- 비즈니스 도메인을 표현하기도 한다.
@Entity
public class User {
@Id @GeneratedValue
private Long id;
private String username;
private String email;
// 생성자, getter, setter
}
2. DTO (Data Transfer Object)
"DTO는 데이터를 전송하기 위한 객체, 즉 계층 간 이동용 컨테이너이다."
특징
- DB와는 무관하며, 계층 간 데이터 전달 또는 API 요청/응답에 사용된다.
- 필요한 필드만 담고, 불필요한 정보는 과감히 생략한다.
- 비즈니스 로직 없이, 순수 데이터 구조만 포함한다.
public class UserDTO {
private String username;
private String email;
// 생성자, getter, setter
}
* 실무에서 DTO 용도
DTO 종류 | 용도 설명 |
요청 DTO | 클라이언트 → 서버로 들어오는 요청 데이터 (@RequestBody 등) |
응답 DTO | 서버 → 클라이언트로 반환되는 응답 데이터 (보안, 구조 정제 필요) |
내부 전달 DTO | Controller ↔ Service 등 계층 간 데이터 이동 |
3. Entity를 직접 노출하면 안 되는 이유
예제
@GetMapping("/users")
public List<User> getUsers() {
return userRepository.findAll(); // ❌ 지양
}
이렇게 Entity를 직접 노출하면...
- 보안 이슈 (예: 비밀번호 노출)
- 필드가 바뀌면 API 응답 구조가 깨짐
- 순환 참조 문제 발생 (Lazy 로딩 등)
이러한 문제들이 발생할 수 있다.
Entity를 직접 반환하지 않고, DTO를 따로 만들어 응답 전용 구조로 바꿔주는 게 좋다.
@GetMapping("/users")
public List<UserDTO> getUsers() {
return userService.getAllUsers().stream()
.map(user -> new UserDTO(user.getUsername(), user.getEmail()))
.collect(Collectors.toList());
}
4. Entity vs DTO 정리
항목 | Entity | DTO |
목적 | DB 테이블과 매핑 | 데이터 전달용 구조체 |
위치 | Repository, Service 내부 | Service ↔ Controller, 또는 API 응답 등 |
로직 포함 | 포함 가능 (비즈니스 메서드 등) | 없음 (순수 데이터 전달) |
민감 정보 | 포함될 수 있음 | 제외함 |
변경 영향도 | DB에 영향 있음 | 없음 (자유롭게 구조 수정 가능) |
5. 결론
Entity는 내부용, DTO는 외부용.
이 원칙 하나만 기억해도 설계가 훨씬 명확해진다.
- Entity: DB와의 직접적인 연결고리
- DTO: 계층 간, 또는 클라이언트와 통신하기 위한 데이터 계약서
- 특히 DTO를 요청/응답 단위로 나눠서 설계하면, API 변경에 유연하고, 보안과 유지보수 측면에서도 훨씬 좋다.