DAO? DTO? VO?

sammy·2023년 9월 25일

백엔드 공부

목록 보기
1/2

오늘은 DAO와 DTO에 대해 정리해보고, DB에 접속해 CRUD(Create Read Update Delete) 작업을 진행하는 예시를 만들어보며 이해를 해보도록 하겠습니다. 추가적으로 VO에 대한 기본적인 개념과 간단한 예시를 들어보겠습니다.

DAO (Data Access Object) 란?

▪️ 데이터베이스와의 상호 작용을 관리하고 데이터베이스 접근 로직을 캡슐화 하는 역할을 합니다.
▪️ 데이터베이스와 직접 상호작용하며, SQL 쿼리 실행을 통해 데이터 검색, 삽입, 수정, 삭제 등의 작업을 수행합니다.

DTO (Data Transfer Object) 란?

▪️ 데이터의 전송을 위한 구조화된 객체를 뜻합니다.
▪️ 서로 다른 계층 간 데이터 전달을 용이하게 하고 데이터를 표현하는데 사용됩니다.
▪️ 데이터 전송 과정에서 객체 형태로 데이터를 유지합니다.
▪️ 주로 필드와 해당 필드에 접근하는 메서드인 getter/setter 로 구성됩니다.

VO (Value Object) 란?

▪️ VO (Value Object)는 비즈니스 도메인의 특정 값을 나타내기 위한 객체로, 데이터의 불변성동등성을 유지하는 것이 중요합니다.
▪️ 불변성 : 한 번 생성된 후에는 그 값을 변경할 수 없습니다.
▪️ 동등성 : VO는 내부 데이터 값에 기반하여 두 객체가 동등하다고 판단될 때 같은 것으로 간주됩니다. 즉, 값 자체가 같으면 VO가 같다고 간주됩니다.

VO 예시코드를 보면 다음과 같습니다.

public class Coordinate {
    private final double latitude;
    private final double longitude;

    public Coordinate(double latitude, double longitude) {
        this.latitude = latitude;
        this.longitude = longitude;
    }

    public double getLatitude() {
        return latitude;
    }

    public double getLongitude() {
        return longitude;
    }

    // 다른 메서드, 유효성 검사 로직 등을 추가할 수 있음
}

다음과 같이 car_no(int AI PK), number (char(20)), model (varchar(20)), price (int), brand (varchar(20)) 필드의 DB가 있을 때, 여기에 CRUD를 진행하는 DAO 코드를 작성해보면 다음과 같습니다.

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!50503 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

--
-- Table structure for table `car`
--

DROP TABLE IF EXISTS `car`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `car` (
  `car_no` int NOT NULL AUTO_INCREMENT,
  `number` char(20) DEFAULT NULL,
  `model` varchar(20) NOT NULL,
  `price` int DEFAULT NULL,
  `brand` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`car_no`),
  UNIQUE KEY `number` (`number`)
) ENGINE=InnoDB AUTO_INCREMENT=12412415 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `car`
--

LOCK TABLES `car` WRITE;
/*!40000 ALTER TABLE `car` DISABLE KEYS */;
INSERT INTO `car` VALUES (1,'12345678','아반떼',2500,'현대'),(2,'55552233','그랜저',4000,'현대'),(3,'77771123','벤츠 C-Class',12000,'메르세데스벤츠');
/*!40000 ALTER TABLE `car` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

우선 데이터를 등록하는 C(Create) 메서드를 작성하면 이와 같습니다.

	@Override
	public int insertCar(CarDto carDto) throws SQLException {
		// 1. sql 작성 
		String sql = "insert into car\n" + 
				"(car_no,number,model,price,brand)\n" + 
				"values(?, ?, ?, ?, ?);";
		
		Connection conn = null;
		PreparedStatement pstmt = null;
		
		try {
			// 2. DB 연결 
			conn = dbUtil.getConnection();
			
			// 3. sql 실행
			
			// 3-1. sql 실행 준비시키기 
			pstmt = conn.prepareStatement(sql);
			
			// 3-2. sql 실행시키기 - 삽입 완료 했다면 1, 아니면 0 반환 
			int cnt = pstmt.executeUpdate();
			return cnt;
			
		} finally {
			// 4. 자원 반납
			
			// 4-1. dbUtil의 close 메서드를 통해 자원 반납 
			dbUtil.close(conn,pstmt);
		}
	}

다음으로 데이터를 전체 조회 혹은 상세 조회하는 R(Read) 메서드를 작성하면 이와 같습니다.

	@Override
	public List<CarDto> sellectAllCars() throws SQLException {
		System.out.println("DAO sellectAll 실행");
		// 1. sql 작성
		String sql = "SELECT * FROM car;";
		
		
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		try {
			// 2. DB와 연결 
			
			// 2-1. dbUtil getConnection 메서드를 통해 db 연결 시키기  
			conn = dbUtil.getConnection(); 
			
			// 3. sql 실행
			
			// 3-1. sql 실행 준비시키기 
			pstmt = conn.prepareStatement(sql);
			// 3-2. sql 실행시켜서 결괏값 가져오기  
			rs = pstmt.executeQuery();
			
			// 4. 조회 데이터 파싱 
			
			// 4-1. carDto 담을 list 만들기 
			List<CarDto> list = new ArrayList<>(); 
			
			while(rs.next()) {
				// 4-2. 가져온 결괏값에서 데이터 파싱해오기 
				int carNo = rs.getInt("car_no");
				String number = rs.getString("number");
				String model = rs.getString("model");
				int price = rs.getInt("price");
				String brand = rs.getString("brand");
				
				// 4-3. CarDto 객체 만들고 리스트에 넣어주기 
				CarDto car = new CarDto(carNo,number,model,price,brand);
				list.add(car);
			}
			
			// 4-4. 완성된 list 반환 
			return list;
			
		}finally {
			// 5. 자원 반납 
			
			// 5-1. dbUtil의 close 메서드를 통해 자원 반납 
			dbUtil.close(conn,pstmt,rs);
		}
	}
	@Override
	public CarDto SearchCar(int carNo) throws SQLException {
		// 1. sql 작성
		String sql = "select *\n" + 
				"from car\n" + 
				"where car_no=?;";
		
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		try {
			// 2. DB와 연결 
			
			// 2-1. dbUtil getConnection 메서드를 통해 db 연결 시키기  
			conn = dbUtil.getConnection(); 
			
			// 3. sql 실행
			
			// 3-1. sql 실행 준비시키기 
			pstmt = conn.prepareStatement(sql);
			
			// 3-2. ?에 값 setting 해주기 
			pstmt.setInt(1, carNo);
						
			// 3-3. sql 실행시켜서 결괏값 가져오기  
			rs = pstmt.executeQuery();
			
			// 4. 조회 데이터 파싱 
			if(rs.next()) {
				// 4-2. 가져온 결괏값에서 데이터 파싱해오기 
				String number = rs.getString("number");
				String model = rs.getString("model");
				int price = rs.getInt("price");
				String brand = rs.getString("brand");
				
				// 4-3. CarDto 객체 만들고 리스트에 넣어주기 
				CarDto car = new CarDto(carNo,number,model,price,brand);
				return car;
			}
			
			return null;
			
		}finally {
			// 4. 자원 반납
			
			// 4-1. 자원 반납 
			dbUtil.close(conn,pstmt,rs);
		}
	}

다음으로 데이터를 수정하는 U(Update) 메서드를 작성하면 이와 같습니다.

	@Override
	public int updateCar(CarDto car) throws SQLException {
		//1. sql 작성
		String sql = "update country\r\n" + 
				"set number=?, model=?,price=?,brand=?\r\n" + 
				"where car_no =?;";
	
		Connection conn = null;
		PreparedStatement pstmt = null;
		
		try {
			//2. DB 연결
			conn = dbUtil.getConnection();
			
			//3. 쿼리 실행
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, car.getNumber());
			pstmt.setString(2, car.getModel());
			pstmt.setDouble(3, car.getPrice());
			pstmt.setString(4, car.getBrand());
			pstmt.setInt(5, car.getCarNo());
			
			int cnt = pstmt.executeUpdate();
			
			return cnt;
			
		} finally {
			dbUtil.close(pstmt, conn);
		} 
	}

마지막으로 D(Delete)를 구현하면 다음과 같습니다.

	@Override
	public int deleteCar(int carNo) throws SQLException {
		// 1. sql 작성
		String sql = "delete from car\n" + 
				"where car_no=?;";
		
		Connection conn = null;
		PreparedStatement pstmt = null;
		
		try {
			// 2. DB 연결
			conn = dbUtil.getConnection();
			
			// 3. sql 실행 
			
			// 3-1. sql 실행 준비시키기 
			pstmt = conn.prepareStatement(sql);
			
			// 3-2. ?에 값 setting 해주기 
			pstmt.setInt(1, carNo);

			// 3-3. sql 실행시키기 - 삽입 완료 했다면 1, 아니면 0 반환 
			int cnt = pstmt.executeUpdate();
			
			return cnt; 
			
		} finally {
			// 4. 자원 반납
			
			// 4-1. dbUtil의 close 메서드를 통해 자원 반납 
			dbUtil.close(conn,pstmt);
		}
	}
profile
누군가에게 도움을 주기 위한 개발자로 성장하고 싶습니다.

0개의 댓글