Backend
home

DAO, DTO, VO란?

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

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)을 꼭 구현할 것