데이터 객체
✒️ 2025-06-24 00:25 내용 수정
DTO(Data Transform Object)
프로세스 간에 데이터를 전달하는 가변 객체
- 과거엔 VO(Value Object)와 병합되었으나, 둘은 다른 용어다.
- 참고 자료 : 위키백과 데이터 전송 객체
- 프로세스 간 통신이 원격 인터페이스(ex: 웹 서비스)로 이루어지면서 각 호출의 비용이 많이 들게 되었고, 호출 비용을 줄이기 위해 오직 하나의 호출로만 서비스 되는 객체를 이용하게 되었다.
- 저장소와 자체 데이터 조회를 제외하고는 어떠한 동작도 하지 않는다.
- 직렬화와 역직렬화 매커니즘을 포함할 수 있다.
- JavaBean도 DTO에 속한다.
public class Person {
private String name;
private int age;
public Person() {}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
VO(Value Object)
한 개 또는 그 이상의 속성들을 묶고 값 그 자체를 표현하기 위한 불변 객체
- 참고 자료 : wikipedia Value object, Nicolo Pignatelli's Value Objects Like a Pro, Livenow's Java VO(Value Obejct)란?
- 계산 및 값 비교 등의 작업을 할 때 사용하거나 reference로 사용한다.
- VO는 3가지 특징을 만족해야 한다.
- 불변성(Immutability) : 값을 생성자에서 처음 설정한 이후엔 변경할 수 없다.
- Setter가 허용되지 않는다.
- 값이 변하지 않기 때문에 reference로 쓸 수 있고, 코드 복잡성을 줄일 수 있다.
- Getter를 추가하기보단 처음엔 클래스 내에 생성자와 private 속성들로만 작성해야 한다.
- 이후 데이터를 변형할 때 더 유용하기 때문
- 생성자, static 메소드, 다른 VO로 새 인스턴스를 생성하는 것을 권장한다.
- 동등성(Value Equality) : 내부 데이터 값이 동등한 두 VO 객체는 같은 객체다.
- 자가유효성(Self Validation) : 유효하지 않은 값을 가진 VO를 생성할 수 없다.
- VO는 값이 생성자에 들어갈 때 그 값들의 일관성을 확인해야 하며, 값들 중 하나가 유효하지 않으면 예외가 발생해야 한다.
- 불변성(Immutability) : 값을 생성자에서 처음 설정한 이후엔 변경할 수 없다.
final class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
DAO(Data Access Object)
데이터에 접근하기 위한 객체
- 참고 자료 : Hyun/Log's Sptring DAO, DTO, VO란? 각각의 개념에 대해 알아보자.
- 웹 서비스와 DB를 연결하는 역할을 하며, 실제 DB에 접근해 데이터를 삽입, 삭제, 조회, 수정(CRUD) 작업을 할 수 있다.
- DAO는 Singleton pattern으로 작성한다.
- 코드 예시 중 try-with-resources 참고.
public class TestDAO {
// singleton pattern
private static TestDAO instance = new TestDAO();
private TestDAO() {}
public TestDAO getInstance() {return instance;}
// 조회 결과 가져오기
public List<TestDTO> selectList() {
List<TestDTO> list = new ArrayList<>();
String sql = "SELECT * FROM TEST_TABLE";
try (Connection conn = DBConnection.getConnection();
PreparedStatement pstmt = prepareStatement(sql);
ResultSet result = pstmt.executeQuery();
)
{
while(result.next()) {
TestDTO dto = new TestDTO();
dto.setName(result.getString("name"));
dto.setNumber(result.getInt("number"));
list.add(dto);
}
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
}
예시
1. DB 접속용 클래스 생성
- DB에 접근하기 위한
Connection클래스를 설정한다.- 상세 예시는 오라클과 연동 등의 내용을 참고.
import java.sql.Connection;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
public class DBConnection {
static DBConnection db;
DataSource ds;
// singleton pattern으로 생성
public static DBConnection getInstance() {
if(db == null) {
db = new DBConnection();
}
return db;
}
// 생성자에서 Context 객체와 DataSource 초기화
public DBConnection() {
try {
InitialContext ic = new InitialContext();
Context ctx = (Context)ic.lookup("java:comp/env");
ds = (DataSource)ctx.lookup("jdbc/oracle_test");
} catch (NamingException e) {
e.printStackTrace();
}
}
// 생성자에서 준비한 정보로 DB에 연결하여 Connection 객체 얻기
public Connection getConnection() {
Connection connec = null;
try {
connec = ds.getConnection();
} catch (Exception e) {
e.printStackTrace();
}
return connec;
}
}
2. DTO 생성
- 필드는
private으로 설정하며, 기본 생성자와 매개변수 생성자 모두를 추가한다. - 필드 접근을 위한 getter와 setter를 설정한다.
public class TestDTO {
// 캡슐화를 위한 private 설정
private String name;
private int number;
// 생성자
public TestDTO() {}
public TestDTO(String name, int number) {
this.name = name;
this.number = number;
}
// getter와 setter
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}
3. DAO 생성
- DB 접속 후 DB에 요청할 SQL 동작을 처리한다.
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import DTO.DBConnection;
import DTO.TestDTO;
public class TestDAO {
static TestDAO dao = null;
// singleton pattern 사용
public static TestDAO getInstance() {
if (dao == null) {
dao = new TestDAO();
}
return dao;
}
// DB에서 조회 결과를 List에 저장하여 반환
public List<TestDTO> selectList() {
List<TestDTO> list = new ArrayList<>();
Connection connec = null;
PreparedStatement prestat = null;
ResultSet result = null;
String sql = "SELECT * FROM TEST_TABLE";
try {
// 1. Connection 얻어오기
connec = DBConnection.getInstance().getConnection();
// 2. sql문 얻어오기
prestat = connec.prepareStatement(sql);
// 3. sql문 실행 결과 처리 객체 얻어오기
result = prestat.executeQuery();
while(result.next()) {
// DTO 객체 생성
TestDTO dto = new TestDTO();
// DTO의 필드에 sql문 결과 테이블의 속성 저장
dto.setName(result.getString("name"));
dto.setNumber(result.getInt("number"));
// list에 DTO 저장
list.add(dto);
}
} catch (Exception e) {
} finally {
// 항상 DB에 연관된 객체는 사용 후 닫아주기
// 생성했던 역순으로 닫기
try {
if (result != null) {
result.close();
}
if (prestat != null) {
prestat.close();
}
if (connec != null) {
connec.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
return list;
}
}