Java

[Java] DAO, DTO, VO, Entity란?

cloud-grace 2024. 5. 22. 17:37

DAO(Data Access Object)

  • DAO는 실제 데이터베이스의 데이터에 접근하기 위한 객체이다.
  • Database 접근 로직과 비즈니스 로직을 분리하기 위해 DAO를 사용한다.
  • DB에 접근하여 CRUD 작업을 수행한다.
  • 코드의 재사용성과 유지보수성을 높인다.

DAO 예제 코드(JDBC)

  • JDBC는 Java에서 데이터베이스와 연결하고 SQL 쿼리를 실행할 수 있는 API이다.
  • JDBC는 SQL을 직접 사용하여 데이터베이스와 상호작용한다.
  • JDBC에서 DAO 역할은 Connection, PreparedStatement, ResultSet 등을 사용하여 직접 SQL 쿼리를 실행하고 결과를 처리한다.
package bookshop.dao;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import bookshop.vo.BookVo;

public class BookDao {
	// DB Connect
    private Connection getConnection() throws SQLException {
        Connection conn = null;

        try {
        	// 1. JDBC Driver 로딩
            Class.forName("org.mariadb.jdbc.Driver");
            // 2. 연결하기
            String url = "jdbc:mariadb://localhost:3306/webdb?charset=utf8";
            conn = DriverManager.getConnection(url, "webdb", "webdb");
        } catch (ClassNotFoundException e) {
            System.out.println("드라이버 로딩 실패:" + e);
        }

        return conn;
    }
	// Insert
    public int insert(BookVo vo) {
        int result = 0;

        try (
                Connection conn = getConnection();
                // 3. Statement 준비
                PreparedStatement pstmt1 = conn.prepareStatement("insert into book(title, author_no) values(?, ?)");
                PreparedStatement pstmt2 = conn.prepareStatement("select last_insert_id() from dual");
        ) {
        	// 4.binding
            pstmt1.setString(1, vo.getTitle());
            pstmt1.setLong(2, vo.getAuthorNo());
            // 5. SQL 실행
            result = pstmt1.executeUpdate();
			// 6. 결과 처리
            ResultSet rs = pstmt2.executeQuery();
            vo.setNo(rs.next() ?  rs.getLong(1) : null);
            rs.close();
        } catch (SQLException e) {
            System.out.println("error:" + e);
        }

        return result;
    }
}

MyBatis

  • MyBatis는 SQL을 매퍼 파일로 분리하여 SQL 쿼리를 명시적으로 관리할 수 있는 프레임워크이다.
  • 동적 SQL을 쉽게 처리할 수 있으며, SQL 쿼리를 XML파일이나 annotation으로 관리한다.
  • MyBatis의 DAO 역할은 DB Connection을 하는 config.xml 파일과 SQL 쿼리를 담고 있는 mapper.xml이 수행한다.

JDBC Template

  • JDBC Template는 Spring에서 제공하는 JDBC의 주요 클래스이다.
  • 반복적인 JDBC 코드를 줄이고, 예외 처리를 일관되게 할 수 있다.
  • JDBC Template의 DAO 역할은 JdbcTemplate 객체를 사용해서 SQL 쿼리를 실행하고 그 결과를 맵핑하는 방식으로 수행한다.

JPA

  • JPA는 Java Persistent API로 Java가 ORM 기술을 통해 작성한 API 표준 명세이다.
  • JPA를 통해 Java 객체와 관계형 데이터베이스 간의 맵핑을 정의하고, 상호작용할 수 있다.
  • 인터페이스를 모아놓은 것이므로 구현체가 필요하다. (ex. Hibernate..)
  • JPA의 DAO는 EntityManager를 사용해서 데이터베이스의 CRUD 작업을 수행한다.

Spring Data JPA

  • Spring Data JPA는 JPA를 기반으로 데이터 접근 계층을 단순화하고 자동화한다.
  • CRUD를 간단히 처리하고 메서드 이름으로 자동으로 쿼리를 생성한다.
  • Spring Data JPA의 DAO는 Repository 인터페이스로 구현한다.

DTO(Data Transfer Object)

  • DTO는 계층(Layer) 간의 데이터 교환을 목적으로 만들어진 객체이다.
  • 네트워크로 데이터 전송하는 데에 사용한다.
  • 여러 데이터 항목을 하나의 객체로 그룹화한다.
  • 계층 : Controller, View, Business, Persistent 등
  • 오직 데이터 교환을 목적으로 하므로 서비스 로직을 가지고 있지 않다.
  • 순수 Data 객체이며, Getter, Setter만 포함한다.

DTO 예제 코드

public class UserDTO {
    private String username;

    // Constructor
    public UserDTO(String username) {
        this.username = username;
    }

    // Getter & Setter
    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }
    
    // toString
    @Override
    public String toString() {
        return "UserDTO{" +
                "username='" + username + '\'' +
                '}';
    }
}
  • lombok으로 더 간단히 표현하면 아래와 같다.
import lombok.*;

@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class UserDTO {
    private String username;
}

VO(Value Object)

  • VO는 데이터를 표현하기 위한 객체이다.
  • VO는 비즈니스 로직이 없으며, 단순 데이터 전달 역할을 한다.
  • 주로 불변 객체로 설계된다.
  • 즉, 생성할 시점의 상태 변경이 불가능하다.
  • DTO와 함께 많이 불리지만, DTO와 달리 Setter가 없다.
  • 즉, DTO는 데이터 조작이 가능하지만 VO는 단순 데이터 이동만을 위한 것이다. (Read-Only)
  • 아래와 같이 @Value 어노테이션을 사용하여 불변 VO를 생성한다.
  • final 필드를 가지고 getter 메서드를 자동으로 생성한다.
  • toString, equals, hashCode도 자동 생성이 되어 있다.
import lombok.Value;

@Value
public class UserVO {
    private String username;
}

Entity

  • Entity는 데이터베이스 테이블과 1:1로 맵핑되는 객체이다.
  • ORM(Object-Relational Mapping) 프레임워크에서는 Entity를 사용해서 데이터베이스와 객체지향 코드를 맵핑한다.
  • Entity는 데이터베이스 테이블의 Row를 표현하며, 고유 식별자 ID를 가지고 있다.
  • DB 테이블에 존재하는 컬럼만을 필드로 가져야 한다.
  • Entity는 DB와 1:1 객체, DTO는 계층 간 데이터 교환 객체이므로 분리해서 사용해야 한다.
  • JPA 사용 시 주로 사용된다.
import lombok.Data;
import javax.persistence.*;

@Entity
@Table(name = "users")
@Data // getter, setter, equals, hashCode, toString, RequiredArgsConstructor
public class UserEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "username")
    private String username;

    @Column(name = "email")
    private String email;
}