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;
}