티스토리 뷰

DB/MyBatis

DAO(Data Access Object) Pattern

xoo | 수진 2023. 8. 2. 23:52

📌 DAO (Data Access Object)

DB에 있는 Data에 접근을 가능하게 해주는 객체

 

 

DAO 클래스

모듈화한 클래스들 중에서 데이터베이스 또는 파일 처리하는 코드만을 관리하는 클래스 파일

 

 

DAO 패턴

  • 비지니스 로직과 DB를 분리하기 위해서 사용하는 패턴
  • DB의 접근을 전담
  • DB를 사용하는 방법이 변경되더라도 로직이 변경되지 않도록 DB 로직을 캡슐화 하여 분리하는 방법

 

 


 

📌 DTO (Data Transfer Object)

getter/setter 메소드만 가지는 데이터 교환을 위한 객체

 

 

DTO 클래스

데이터를 다른 logic에게 전송 및 반환할 때 효율적으로 데이터를 전송 및 사용할 수 있게 하는 클래스

 

 

 


 

 

 

 

 


 

📌JDBC(Java Database Connectivity)

 

 

1) jar 파일(driver) 다운로드 및 classpath 지정
2) import java.sql.*    //JDBC 인터페이스
3) 드라이버 로딩 (sqlite나 JDBC 4.0이상은 필요없음)
4) DriverManager.getConnection()
5) Statement를 사용해서 SQL 쿼리 사용, ResultSet으로 결과 받기
6) Close() 하기

 

 


 

 

💡 진행과정

scott 계정 dept 테이블의 모든 정보를 SELECT하는 프로그램

1. Main에서 Service 객체를 생성하면, Service 생성자는 DAO 객체를 생성하고 드라이버 로딩을 한다.
2. Main에서 Service 클래스의 select() 메소드를 호출한다.
3. 호출된 Service 클래스의 select() 메소드는 DB에 접속하고, 접속한 후 얻은 Connection 객체를 DAO 클래스의 select() 메소드로 전달한다.
4. DAO 클래스의 select() 메소드는 전달받은 Connection 객체를 이용해 실제 DB에 접근하여 SQL문을 실행하고, 실행 결과를 받아와서 Service 클래스로 리턴한다.
5. Service 클래스는 다시 Main으로 결과값을 리턴한다.
6. Main에서 결과값을 받아 사용할 수 있게 된다. 

 

 

 

 

DeptDTO.java
DeptDTO 클래스는 dept 테이블의 레코드 하나를 나타내는 모델 클래스이다. DB에서 꺼내온 데이터를 DTO를 이용해 저장하여 다른 Logic으로 전송할 수 있게 된다. 생성자와 getter / setter 메서드도 설정한다.

package com.dto;

//dept 테이블의 하나의 행(레코드)을 저장하는 용도
public class DeptDTO {
	
	// DeptDTO 클래스의 변수명은 dept테이블의 컬럼명과 동일하게 지정
	int deptno;  // dept테이블의 deptno 컬럼 저장
	String dname; // dept테이블의 dname 컬럼 저장
	String loc;  // dept테이블의 loc 컬럼 저장
	
	// 생성자
	public DeptDTO() {}

	public DeptDTO(int deptno, String dname, String loc) {
		this.deptno = deptno;
		this.dname = dname;
		this.loc = loc;
	}

	// getter, setter
	public int getDeptno() {
		return deptno;
	}

	public void setDeptno(int deptno) {
		this.deptno = deptno;
	}

	public String getDname() {
		return dname;
	}

	public void setDname(String dname) {
		this.dname = dname;
	}

	public String getLoc() {
		return loc;
	}

	public void setLoc(String loc) {
		this.loc = loc;
	}

	// toString()
	@Override
	public String toString() {
		return deptno+"\\t"+dname+"\\t"+loc;
	}
	
}

 

 

DeptService.java (interface)

package com.service;

import java.util.List;

import com.dto.DeptDTO;
import com.exception.DuplicatedDeptnoException;

// dept 테이블의 데이터를 가공하는 역할 ==> 비즈니스 로직 처리 및 트랜잭션 처리 담당.
public interface DeptService {

	public List<DeptDTO> findAll();
	
	// DML
	public int insert(DeptDTO dto) throws DuplicatedDeptnoException;
	public int update(DeptDTO dto);
}

 

 

DeptServiceImpl.java ( implements DeptService )
Service 클래스는 Business logic을 처리하는 클래스로서, 메인 클래스와 DAO 클래스 사이를 연결해준다. DB연동에 필요한 네 가지 정보를 인스턴스 변수로 저장하고, Service에서 사용할 DAO 객체를 선언한다. 

package com.service;

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

import com.dao.DeptDAO;
import com.dto.DeptDTO;
import com.exception.DuplicatedDeptnoException;

// 오라클 데이터베이스와 연결하기 위해 Connection을 얻는 작업을 하기 위한 클래스
// Connection 얻는 이유? 트랜잭션을 처리하려고
// 얻은 Connection을 실제 데이터베이스와 연동하는 DeptDAO 클래스에 인자로 전달하여 사용된다.
public class DeptServiceImpl implements DeptService {

	String driver = "oracle.jdbc.driver.OracleDriver";
	String url = "jdbc:oracle:thin:@localhost:1521:xe";
	String userid = "SCOTT";
	String passwd = "TIGER";

	public DeptServiceImpl() {
		try {
			Class.forName(driver);    // 드라이버 로딩
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	// < select 기능하는 메서드 >
	// Connection 까지만 얻는다. 나머지 작업은 DAO에서 처리
	@Override
	public List<DeptDTO> findAll(){
		
		List<DeptDTO> list = null;   // ★
		Connection con = null;

		// Connection 맺기
	    try{
	       con = DriverManager.getConnection(url, userid, passwd);
	       // DAO 접근
	       DeptDAO dao = new DeptDAO();    // ★
	       list = dao.findAll(con);   // ★
	    }catch(SQLException e){
	    	e.printStackTrace();
	    }finally {                  // close()
			try {
				if(con != null)con.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return list;   // ★ 리턴
	}

 

 

 

DeptDAO.java

DAO 클래스는 실제 DB와 연동하는 클래스이다. Service 클래스의 select메소드에서 DAO클래스의 select메소드를 호출하며 Connection 객체를 인자로 전달하면, DAO 클래스의 select 메소드에서는 전달받은 Connection 객체를 이용해 SQL문을 실행하고, 실행한 결과값을 ResultSet 객체로 받아온다. ResultSet 객체에서 레코드를 하나씩 꺼내서 list에 추가 시키면, list에는 dept 테이블의 모든 레코드가 하나씩 저장된다. 이후 ResultSet, PreparedStatement 연결을 해제하고 list를 리턴한다.

package com.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 com.dto.DeptDTO;
import com.exception.DuplicatedDeptnoException;

// 실제 데이터베이스 (Oracle의 dept테이블)와 연동하는 클래스
// dept 테이블의 하나의 레코드는 DeptDTO에 저장
// 누적하기 위하여 ArrayList<DeptDTO>를 사용
// 주의할 점 : Connection을 DAO 클래스에서 close()하면 안되고 반드시 Service 클래스에서 close() 시켜야한다.
public class DeptDAO {

	// < select 기능하는 메서드 >
	public List<DeptDTO> findAll(Connection con){
		
		// 다형성 통해 DeptDTO 누적용
		List<DeptDTO> list = new ArrayList<DeptDTO>();
		PreparedStatement pstmt=null;
	    ResultSet rs = null;
	    try{
	       String sql = "select deptno as no, dname, loc from dept";
	       pstmt = con.prepareStatement(sql); //에러발생시
	       rs = pstmt.executeQuery();
	       // 결과값인 ResultSet에서 데이터를 얻기
	       while(rs.next()) {
	    	  int deptno = rs.getInt("no"); // getInt(1) 가능
	    	  String dname = rs.getString("dname");  // getString(2)
	    	  String loc = rs.getString("loc");  // // getString(3)
	    	  // 생성자 통해 DTO에 저장. 한 번 돌때마다 DTO 생성.
	    	  DeptDTO dto = new DeptDTO(deptno, dname, loc);
	    	  // 누적
	    	  list.add(dto);
	       }
	    }catch(SQLException e){
	    	e.printStackTrace();
	    }finally {
			try {
				//역순
				if(rs != null)rs.close();
				if(pstmt != null)pstmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		
		 return list;
	}//

 

 

 

DeptMain.java
메인에서는 Service 객체를 사용한다.
Service 객체 생성 후, Service 클래스의 select메소드를 호출하여 반환된 결과값을 ArrayList<DeptDTO> 타입으로 저장한다. 메인에 try~catch 문을 작성하면 Service 클래스와 DAO 클래스에서 발생된 예외를 한번에 처리한다. 이후 받아온 List의 데이터를 순회하며 출력하게 된다.

import java.util.List;
import java.util.Scanner;

import com.dto.DeptDTO;
import com.exception.DuplicatedDeptnoException;
import com.service.DeptService;
import com.service.DeptServiceImpl;

public class DeptMain {

	public static void main(String[] args) {

		// 화면처리 추가
		while(true) {
			Scanner scan = new Scanner(System.in);
			System.out.println("1. 전체목록");
			System.out.println("2. 저장하기");
			System.out.println("3. 수정하기");
			System.out.println("0. 종료");
			System.out.println("-----------------------");
			
			// 문자열로 읽기
			String num = scan.nextLine();     // 한 줄 읽기
			if("1".equals(num)) {      // 만약 1이면. 문자열 비교는 equals
				// 서비스 연동
				DeptService service = new DeptServiceImpl();    // 다형성으로 객체 생성
				List<DeptDTO> list = service.findAll();
				System.out.println("부서번호\\t 부서명\\t 부서위치");
				System.out.println("-----------------------");
				for (DeptDTO dto : list) {
					System.out.println(dto);      // dto.toString() 포맷을 잘 만들어야한다. 
				}
			}else if("2".equals(num)) {
				System.out.println("부서번호를 입력하시오");
				String deptno = scan.next();
				System.out.println("부서명을 입력하시오");
				String dname = scan.next();
				System.out.println("부서위치를 입력하시오");
				String loc = scan.next();
				// 입력받은 3가지 값을 DTO에 저장해서 서비스를 거쳐 DAO까지 전달한다.
				DeptDTO dto = new DeptDTO(Integer.parseInt(deptno), dname, loc);
				// 서비스 연동
				DeptService service = new DeptServiceImpl();
				int n=0;
				try {
					n = service.insert(dto);
				} catch (DuplicatedDeptnoException e) {
					System.out.println(e.getMessage());
				}
				System.out.println(n+" 개가 저장되었습니다");
				
			}else if("3".equals(num))	{
				System.out.println("수정할 부서번호를 입력하시오");
				String deptno = scan.next();
				System.out.println("수정할 부서명을 입력하시오");
				String dname = scan.next();
				System.out.println("수정할 부서위치를 입력하시오");
				String loc = scan.next();
				DeptDTO dto = new DeptDTO(Integer.parseInt(deptno), dname, loc);
				
				// 서비스 연동
				DeptService service = new DeptServiceImpl();
				int n= service.update(dto);
				System.out.println(n+" 개가 수정되었습니다");
				
			}else if("0".equals(num)) {
				System.out.println("프로그램 종료");
				System.exit(0);    // exit : 프로그램 정상종료 
			}
			
		}//end while
		
	}//end main

}//end class

 

 

 

DuplicatedDeptnoException.java

package com.exception;

// Exception을 상속받는 사용자 정의 예외클래스
// => 예외 발생 시 try~catch 또는 throws에 사용할 수 있다.
public class DuplicatedDeptnoException extends Exception{

	// 필요시 변수, 메서드 추가 가능
	
	public DuplicatedDeptnoException(String message) {
		super(message);
	}
}

'DB > MyBatis' 카테고리의 다른 글

Mybatis - 조건문  (0) 2023.08.07
Mybatis - Dynamic SQL  (0) 2023.08.07
Mybatis - 환경설정 및 SELECT 예제  (0) 2023.08.04
트랜잭션(Transaction) 처리  (0) 2023.08.03
JDBC  (0) 2023.08.01
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함