Backend
home

DAO, DTO, VO란?

생성 일시
2025/05/04 15:19
태그
Java
게시일
2025/05/05
최종 편집 일시
2025/05/08 09:50

1. DAO (Data Access Object)

역할: 데이터베이스(DB)와 직접 소통하는 객체.
책임: SQL 실행, CRUD 수행, Entity 객체 반환.
왜 필요한가?
데이터 접근 로직을 분리해서 비즈니스 로직과 섞이지 않게 하기 위함.
나중에 DBMS가 변경되어도, DAO만 수정하면 서비스 로직은 그대로 사용 가능.
@Repository public class UserDao { @Autowired private JdbcTemplate jdbcTemplate; public User findById(Long id) { String sql = "SELECT * FROM users WHERE id = ?"; return jdbcTemplate.queryForObject(sql, new Object[]{id}, new BeanPropertyRowMapper<>(User.class)); } }
Java
복사
여기서 UserDao는 DB 접근을 담당하는 DAO.

2. DTO (Data Transfer Object)

역할: 계층 간 데이터 전송을 위한 객체.
책임: 데이터를 담아서 컨트롤러 서비스 외부 시스템 간에 이동할 때 사용.
왜 필요한가?
엔티티를 외부로 노출하는 것은 보안, 유지보수 측면에서 위험하다.
불필요한 데이터 노출 방지 (민감한 필드 제외)
API 스펙에 맞는 형태로 변환 가능 (예: JSON 구조 맞추기)
public class UserResponseDto { private Long id; private String username; private String email; // 생성자, Getter }
Java
복사
엔티티 User 는 비밀번호, 가입일자 등 여러 필드가 있지만, 클라이언트에게는 id, username, email만 전송해줌.
DTO 패턴의 핵심: “전송에 적합한 형태로 데이터를 포장하는 것”.

3. VO (Value Object)

역할: 값 자체를 표현하는 객체. 불변(immutable) 성격.
책임: 값의 동등성 “값 자체”로 판단하고, 객체의 참조가 아닌 값 비교가 핵심.
왜 필요한가?
불변 객체이므로 스레드 세이프(thread-safe).
비즈니스 규칙에서 값으로 취급하는 데이터를 표현하기에 적합.
예시: 주소, 전화번호, 금액(Money) 같은 것들.
public class Address { private final String city; private final String street; public Address(String city, String street) { this.city = city; this.street = street; } // Getter, equals, hashCod }
Java
복사
Address는 VO로 취급. new Address("서울", "강남구") 두 객체가 값이 같으면 같은 것으로 봄.

4. 왜 DTO로 데이터를 전송해야 하나?

1. 보안

엔티티에는 민감한 데이터(비밀번호, 권한, 내부 ID)가 포함되어 있음.
DTO는 필요한 데이터만 담아서 불필요한 노출 방지 가능.

2. 유지보수

API 스펙이 바뀌어도 DTO만 수정하면 되고, 엔티티나 DB 구조는 그대로 유지 가능.

3. 계층 분리

Controller, Service, Repository 계층이 깔끔하게 분리됨.
엔티티가 직접 외부로 노출되지 않으므로, 엔티티와 API의 독립성 확보.

4. 성능 최적화

엔티티를 직접 반환할 경우 불필요한 필드까지 직렬화됨 → 네트워크 비용 증가.
DTO는 필요한 필드만 골라서 보내므로 전송 데이터가 가볍다.

5. 요약

구분
역할
특징
예시
DAO
DB 접근 객체
SQL 실행, CRUD 담당
UserDao, ProductDao
DTO
계층 간 데이터 전송 객체
API, 클라이언트 데이터 포장
UserResponseDto, LoginRequestDto
VO
값 객체
불변, 값 비교
Address, Money, PhoneNumber

6. 실무에선 어떻게?

Controller Service Repository
Controller에서는 Request DTO로 데이터를 받고,
Service에서는 비즈니스 로직 수행 후 Response DTO로 반환.
Repository(DAO)에서는 Entity로 DB와 소통.
[Client][Controller: RequestDTO][Service: Entity][DAO: DB][Service: ResponseDTO][Controller][Client]
Java
복사
엔티티를 절대 외부 API로 직접 반환하지 말 것! (보안 문제, 유지보수 문제)
DTO는 요구사항에 맞게 유연하게 설계 (필드 선택 가능)
VO는 불변으로 설계하고, 값 비교 로직 (equals, hashCode)을 꼭 구현할 것