🚩 DAO (Data Access Object) 패턴 소개
소프트웨어 개발에서 데이터베이스와의 상호작용은 매우 중요합니다.
그러나 데이터베이스 접근 로직이 코드에 직접 삽입되면, 유지보수와 테스트가 어려워질 수 있습니다.
데이터베이스에 저장된 정보를 쉽게 관리하고 접근하기 위해, DAO (Data Access Object) 패턴이 사용됩니다.
이 글에서는 DAO 패턴의 개념을 쉽게 설명하고, 실제 예시를 통해 이해를 돕겠습니다
⭐ DAO 패턴의 개념
DAO 패턴은 데이터를 저장하고 가져오는 과정에서 발생하는 복잡성을 줄여주는 설계 패턴입니다.
이를 위해 다음과 같은 역할을 합니다.
- 추상화: 데이터베이스와의 상호작용을 단순화합니다. 비즈니스 로직(애플리케이션의 주요 기능)은 데이터가 어떻게 저장되고 가져오는지에 대한 세부 정보를 몰라도 작동할 수 있습니다.
- 구분: 데이터 접근 로직과 비즈니스 로직을 분리하여 관리합니다. 이렇게 하면 데이터베이스 구조나 기술을 변경할 때, 비즈니스 로직에 영향을 주지 않고 쉽게 수정할 수 있습니다.
예를 들어, 사용자의 정보를 저장하는 애플리케이션이 있다고 가정해 봅시다. DAO 패턴을 사용하면 사용자의 정보를 저장하고 가져오는 기능을 UserDAO라는 클래스로 만들 수 있습니다. 이 클래스는 데이터베이스와 직접 상호작용하며, 비즈니스 로직에서는 이 클래스를 통해 사용자 정보를 쉽게 다룰 수 있습니다.
⭐ 데이터베이스 변경의 용이성
DAO 패턴의 큰 장점 중 하나는 데이터베이스를 변경할 때 유연하다는 점입니다.
예를 들어, 처음에는 MySQL 데이터베이스를 사용하다가 MongoDB로 변경하고 싶다면, UserDAO 클래스의 구현만 수정하면 됩니다.
비즈니스 로직에서는 여전히 같은 인터페이스를 사용하므로, 코드의 다른 부분은 손대지 않아도 됩니다.
⭐ DAO 구현 방법
DAO를 구현할 때는 일반적으로 인터페이스와 그 구현 클래스를 정의합니다.
인터페이스에는 데이터베이스와의 상호작용을 위한 메서드가 포함되며, 구현 클래스에서는 이러한 메서드를 구체적으로 정의합니다.
이 과정에서 JDBC, JPA, Hibernate 등 다양한 ORM(Object-Relational Mapping) 도구를 사용할 수 있습니다.
⭐ 간단한 예시
아래는 Spring에서 DAO 패턴을 사용하는 간단한 예시입니다. 이 예시는 사용자의 정보를 관리하는 User 객체와 이를 위한 UserDAO 인터페이스 및 그 구현 클래스를 보여줍니다.
✅ User 클래스
public class User {
private Long id;
private String name;
private String email;
// 생성자, 게터, 세터
public User(Long id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
// Getters and Setters
}
✅ UserDAO 인터페이스
import java.util.List;
public interface UserDAO {
void addUser(User user);
User getUser(Long id);
List<User> getAllUsers();
void updateUser(User user);
void deleteUser(Long id);
}
사용자 정보를 처리하기 위한 메서드를 정의합니다.
✅ UserDAOImpl 클래스
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public class UserDAOImpl implements UserDAO {
private final JdbcTemplate jdbcTemplate;
public UserDAOImpl(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public void addUser(User user) {
String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
jdbcTemplate.update(sql, user.getName(), user.getEmail());
}
@Override
public User getUser(Long id) {
String sql = "SELECT * FROM users WHERE id = ?";
return jdbcTemplate.queryForObject(sql, new Object[]{id},
(rs, rowNum) -> new User(rs.getLong("id"), rs.getString("name"), rs.getString("email")));
}
@Override
public List<User> getAllUsers() {
String sql = "SELECT * FROM users";
return jdbcTemplate.query(sql,
(rs, rowNum) -> new User(rs.getLong("id"), rs.getString("name"), rs.getString("email")));
}
@Override
public void updateUser(User user) {
String sql = "UPDATE users SET name = ?, email = ? WHERE id = ?";
jdbcTemplate.update(sql, user.getName(), user.getEmail(), user.getId());
}
@Override
public void deleteUser(Long id) {
String sql = "DELETE FROM users WHERE id = ?";
jdbcTemplate.update(sql, id);
}
}
실제 데이터베이스와 상호작용하는 구현체입니다.
✅ UserService 클래스
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserService {
private final UserDAO userDAO;
@Autowired
public UserService(UserDAO userDAO) {
this.userDAO = userDAO;
}
public void createUser(String name, String email) {
User user = new User(null, name, email);
userDAO.addUser(user);
}
public User findUser(Long id) {
return userDAO.getUser(id);
}
public List<User> listUsers() {
return userDAO.getAllUsers();
}
public void modifyUser(User user) {
userDAO.updateUser(user);
}
public void removeUser(Long id) {
userDAO.deleteUser(id);
}
}
비즈니스 로직을 처리하며 DAO를 사용하여 사용자 정보를 관리합니다.
⭐ 테스트와 유지보수의 장점
DAO 패턴은 단순히 데이터베이스와의 상호작용을 효율적으로 관리할 뿐만 아니라, 테스트와 유지보수에도 큰 장점을 제공합니다.
예를 들어, 단위 테스트를 진행할 때, DAO를 목(mock) 객체로 쉽게 교체할 수 있어 데이터베이스와의 의존성을 줄일 수 있습니다.
🚩 결론
결론적으로, DAO 패턴은 데이터 접근을 보다 구조적이고 효율적으로 만들어주는 강력한 도구입니다.
개발 과정에서 DAO를 적극 활용하면 코드의 품질을 높이고, 변화에 유연하게 대응할 수 있습니다.
⭐ DTO와 DAO
✅ DTO (Data Transfer Object)
DTO는 데이터를 전송하기 위한 객체로, 속성을 담고 있으며 데이터베이스와의 직접적인 상호작용을 포함하지 않습니다.
// UserDTO.java
public class UserDTO {
private Long id;
private String name;
private String email;
// 생성자
public UserDTO(Long id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
// Getters and Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
- 목적: UserDTO는 사용자 정보를 전송하기 위해 정의된 객체입니다. 예를 들어, 클라이언트에서 서버로 사용자 정보를 전송하거나 서버에서 클라이언트로 응답할 때 사용됩니다.
- 구조: DTO는 데이터 속성만 포함하며, 비즈니스 로직이나 데이터베이스 접근에 대한 내용은 포함하지 않습니다.
✅ DAO (Data Access Object)
DAO는 데이터베이스와의 상호작용을 관리하는 객체입니다.
import java.util.List;
// UserDAO.java
public interface UserDAO {
void addUser(UserDTO user);
UserDTO getUser(Long id);
List<UserDTO> getAllUsers();
void updateUser(UserDTO user);
void deleteUser(Long id);
}
// UserDAOImpl.java
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public class UserDAOImpl implements UserDAO {
private final JdbcTemplate jdbcTemplate;
public UserDAOImpl(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public void addUser(UserDTO user) {
String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
jdbcTemplate.update(sql, user.getName(), user.getEmail());
}
@Override
public UserDTO getUser(Long id) {
String sql = "SELECT * FROM users WHERE id = ?";
return jdbcTemplate.queryForObject(sql, new Object[]{id},
(rs, rowNum) -> new UserDTO(rs.getLong("id"), rs.getString("name"), rs.getString("email")));
}
@Override
public List<UserDTO> getAllUsers() {
String sql = "SELECT * FROM users";
return jdbcTemplate.query(sql,
(rs, rowNum) -> new UserDTO(rs.getLong("id"), rs.getString("name"), rs.getString("email")));
}
@Override
public void updateUser(UserDTO user) {
String sql = "UPDATE users SET name = ?, email = ? WHERE id = ?";
jdbcTemplate.update(sql, user.getName(), user.getEmail(), user.getId());
}
@Override
public void deleteUser(Long id) {
String sql = "DELETE FROM users WHERE id = ?";
jdbcTemplate.update(sql, id);
}
}
- 목적: UserDAO는 사용자 정보를 데이터베이스에 추가, 조회, 수정 및 삭제하는 메서드를 정의합니다. UserDAOImpl은 이 메서드들을 구현하여 실제 데이터베이스와 상호작용합니다.
- 구조: DAO는 데이터베이스 쿼리 및 그 결과를 처리하는 로직을 포함하고 있습니다. 이때 DTO를 사용하여 데이터를 전달합니다.
⭐ DTO와 DAO의 차이 요약
- 목적:
- DTO: 데이터를 전송하는 데 중점을 둡니다. UserDTO는 사용자 정보를 담기 위한 객체입니다.
- DAO: 데이터베이스와의 상호작용을 처리합니다. UserDAO와 UserDAOImpl은 데이터베이스에서 사용자 정보를 관리하는 데 필요한 메서드를 정의하고 구현합니다.
- 구조:
- DTO: 속성만 포함하며 비즈니스 로직이나 데이터베이스 접근을 포함하지 않습니다.
- DAO: 데이터베이스 쿼리 및 관련 로직을 포함하여, 비즈니스 로직과의 상호작용을 관리합니다.
- 사용 위치:
- DTO: 데이터 전송이 필요한 경우, 예를 들어 API 응답이나 요청 시 사용됩니다.
- DAO: 비즈니스 로직에서 호출되어 데이터베이스 작업을 수행합니다.
⭐ DAO와 DTO를 함께 사용하는 이유
대부분의 프로젝트에서는 DAO와 DTO를 함께 사용하는 것이 일반적입니다. 이 두 개념은 서로 보완적이며, 각각의 역할이 다르기 때문에 함께 사용하면 더 효율적이고 구조적인 애플리케이션을 만들 수 있습니다.
- 역할 분리:
- DAO는 데이터베이스와의 상호작용을 처리하고, CRUD 작업을 수행하는 데 특화되어 있습니다.
- DTO는 데이터 전송을 위한 객체로, 네트워크나 API를 통해 데이터를 주고받는 역할을 합니다.
- 유지보수성:
- 데이터베이스 접근 로직과 데이터 전송 로직을 분리하면, 한쪽의 변경이 다른 쪽에 미치는 영향을 최소화할 수 있습니다. 예를 들어, 데이터베이스 구조를 변경하더라도 DTO는 영향을 받지 않습니다.
- 테스트 용이성:
- DAO는 데이터베이스와의 의존성이 있기 때문에, 이를 목(mock) 객체로 대체하여 테스트할 수 있습니다. DTO는 단순한 데이터 구조이므로, 비즈니스 로직에서 쉽게 사용할 수 있습니다.
'기술 지식 쌓아가기 📚 > Backend 🍔' 카테고리의 다른 글
[DB] JPA와 ORM: 데이터베이스와의 스마트한 연결 (0) | 2024.10.08 |
---|---|
[DB] Spring에서의 데이터베이스 처리: JDBC vs JPA (0) | 2024.10.08 |
[Framework] 웹 개발 프레임워크 비교: Spring Boot와 Node.js의 장단점 (1) | 2024.10.07 |
[Spring] Java Message Service (JMS) 이해하기 : 비동기 메시징 🍃 (1) | 2024.10.06 |
[Spring] REST vs SOAP: 두 웹 서비스 아키텍처의 비교 🍃 (0) | 2024.10.06 |