DAO 패턴
#01. DAO 패턴의 이해
1) DAO(Data Access Object) 패턴
- DAO 패턴은 표준 J2EE 디자인 패턴들 중 하나로서 다음과 같은 요소들이 있다.
- DAO 인터페이스
- DAO 인터페이스를 구현한 클래스
- 데이터 전송 객체(Beans에 대한 객체)=DTO(Data Transform Object)
- 여러가지 변수를 전송하기 위해 자바빈즈(여러가지 복합적인 것을 묶는 최소단위)를 사용한다.
- 이 패턴을 사용하여 저수준의 데이터 엑세스와 고급 비지니스 로직을 분리 할 수 있다.
2) DAO 패턴 작성 과정
- 처리할 데이터가 저장되기 위한 데이터 베이스 테이블의 구조를 JavaBeans로 표현한다.
- 데이터의 입력, 수정, 삭제, 조회(단일, 다중)의 기능을 명시한 Interface를 정의한다.
- Interface를 상속받는 클래스를 준비하고, Interface에서 명시하고 있는 메서드들을 재정의한다.
#02. DAOEx 프로젝트 구성
1) 사용할 클래스와 라이브러리
- study.java.daoex.model 패키지
- 프로그램에서 사용할 데이터의 구조를 정의한다.
- study.java.daoex.dao 패키지
- 데이터베이스에 대한 입출력 기능을 인터페이스 형태로 설계한다.
- study.java.daoex.dao.impl 패키지
- 설계된 인터페이스를 상속하여 실제로 동작할 기능을 구현한다.
#03. JavaBeans 만들기
- 자바빈즈 생성
- 데이터베이스의 값을 보고 변수를 만들어 자바빈즈를 만든다.
mysql> desc department;
+--------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+----------------+
| deptno | int(4) | NO | PRI | NULL | auto_increment |
| dname | varchar(16) | NO | | NULL | |
| loc | varchar(10) | YES | | NULL | |
+--------+-------------+------+-----+---------+----------------+
package study.java.daoex.model;
/** department 테이블 구조에 맞춘 Java Beans 생성 */
// 자바빈즈 - 여러가지 복합적인 것을 사용하기 쉽게 묶는 최소 단위
public class Department {
private int deptno;
private String dname;
private String loc;
public Department(int deptno, String dname, String loc) {
super();
this.deptno = deptno;
this.dname = dname;
this.loc = loc;
}
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;
}
@Override
public String toString() {
return "Department [deptno=" + deptno + ", dname=" + dname + ", loc=" + loc + "]";
}
}
#04. DAO 패턴 구성 실습
- DAO로 구현해야하는 기능을 인터페이스로 정의한다.
import java.util.List;
import study.java.daoex.model.Department;
public interface DepartmentDao {
/**
* 데이터를 저장한다. (INSERT 구문을 실행)
* @param params 저장할 값을 담고 있는 Department 클래스의 객체
* @return int 저장된 행의 primary Key값
*/
public int insert(Department params);
/**
* 데이터를 삭제한다. (DELETE 구문을 실행)
* @param params WHERE절 조건값으로 사용할 deptno
* @return int 삭제된 데이터의 수
*/
public int delete(int params);
/**
* 데이터를 갱신한다. (UPDATE 구문을 실행)
* @param params Department 클래스의 객체
* @return int 수정된 데이터의 수
*/
public int update(Department params);
/**
* 데이터 한 건을 조회한다. (WHERE절을 사용한 SELECT문을 실행)
* @param params WHERE절 조건값으로 사용할 deptno
* @return Department 조회된 데이터를 포함한 객체
*/
public Department selectOne(int params);
/**
* 데이터 목록을 조회한다. (SELECT를 사용한 전체 데이터 조회)
* @return List 조회된 데이터를 포함한 컬렉션
*/
public List<Department> select();
}
- 데이터 처리 단계 (Insert, Delete, Update, 하나만조회, 전체조회)
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import study.java.daoex.dao.DepartmentDao;
import study.java.daoex.model.Department;
public class DepartmentDaoImpl implements DepartmentDao{
/** 데이터 베이스 접속 객체 */
private Connection conn;
/** 생성자를 통해서 데이터베이스 접속 객체를 전달 받는다.*/
public DepartmentDaoImpl (Connection conn) {
this.conn = conn;
}
// 메서드가 재정의되었으므로 먼저 리턴값부터 정리
@Override
public int insert(Department params) {
int result = 0;
/** 실행할 SQL구문 정의*/
String sql = "INSERT INTO department (dname,loc) VALUES(?,?)";
/** SQL 구문 실행하기 위한 객체*/
// -->import java.sql.preparedStatement;
PreparedStatement pstmt = null;
// -->import java.sql.ResultSet;
ResultSet rs = null;
/** SQL 구문 처리하기*/
try {
// pstmt 객체 할당
pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
// 템플릿에 데이터 설정
pstmt.setString(1, params.getDname());
pstmt.setString(2, params.getLoc());
// SQL문 실행하기 --> 결과 행의 수를 리턴할 변수에 대입함
pstmt.executeUpdate();
// Primary Key 받기
rs = pstmt.getGeneratedKeys();
rs.next();
result = rs.getInt(1);
} catch (SQLException e) {
System.out.println("MySQL SQL Fail : " + e.getMessage());
} finally {
if(rs != null) {
// 객체 닫기
try {
rs.close();
} catch (Exception e) {}
}
if (pstmt != null) {
// 객체 닫기
try {
pstmt.close();
} catch (SQLException e) {}
}
}
return result;
}
@Override
public int delete(int params) {
int result = 0;
/** 실행할 SQL 구문 정의 */
String sql = "DELETE FROM department WHERE deptno=?";
/** SQL 구문 실행하기 위한 객체 */
// --> import java.sql.PreparedStatement;
PreparedStatement pstmt = null;
/** SQL 구문 처리하기 */
try {
// pstmt 객체 할당
pstmt = conn.prepareStatement(sql);
// 템플릿에 데이터 설정
pstmt.setInt(1, params);
// SQL문 실행하기 --> 결과 행의 수를 리턴할 변수에 대입함
result = pstmt.executeUpdate();
} catch (SQLException e) {
System.out.println("MySQL SQL Fail : " + e.getMessage());
} finally {
if (pstmt != null) {
// 객체 닫기
try {
pstmt.close();
} catch (SQLException e) {}
}
}
return result;
}
@Override
public int update(Department params) {
int result = 0;
/** 실행할 SQL 구문 정의 */
String sql = "UPDATE department SET dname=?, loc=? WHERE deptno=?";
/** SQL 구문 실행하기 위한 객체 */
// --> import java.sql.PreparedStatement;
PreparedStatement pstmt = null;
/** SQL 구문 처리하기 */
try {
// pstmt 객체 할당
pstmt = conn.prepareStatement(sql);
// 템플릿에 데이터 설정
pstmt.setString(1, params.getDname());
pstmt.setString(2, params.getLoc());
pstmt.setInt(3, params.getDeptno());
// SQL문 실행하기 --> 결과 행의 수를 리턴할 변수에 대입함
result = pstmt.executeUpdate();
} catch (SQLException e) {
System.out.println("MySQL SQL Fail : " + e.getMessage());
} finally {
if (pstmt != null) {
// 객체 닫기
try {
pstmt.close();
} catch (SQLException e) {}
}
}
return result;
}
@Override
public Department selectOne(int params) {
Department result = null;
/** 실행할 SQL 구문 정의 */
String sql = "SELECT deptno, dname, loc FROM department WHERE deptno=?";
/** SQL 구문 실행하기 위한 객체 */
// --> import java.sql.PreparedStatement
PreparedStatement pstmt = null;
// --> import java.sql.ResultSet;
ResultSet rs = null;
/** SQL 구문 처리하기 */
try {
pstmt = conn.prepareStatement(sql);
// 템플릿에 데이터 설정
pstmt.setInt(1, params);
// SQL문 실행하기 --> 결과 행 리턴됨
rs = pstmt.executeQuery();
// 조회 결과의 첫 번째 줄로 이동
boolean first = rs.next();
if(first) {
// SELECT절에 명시한 컬럼 이름을 사용하여 데이터 추출
int deptno = rs.getInt("deptno");
String dname = rs.getString("dname");
String loc = rs.getString("loc");
// 리턴할 객체에 조회한 값을 사용하여 객체를 할당한다.
result = new Department(deptno, dname, loc);
} else {
System.out.println("조회 결과가 없습니다.");
}
} catch (SQLException e) {
System.out.println("MySQL SQL Fail : " + e.getMessage());
} finally {
// 객체를 생성한 순서의 역순으로 객체를 닫는다.
if ( rs != null) {
try {
rs.close();
} catch (SQLException e) { }
}
if ( pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) { }
}
}
return result;
}
@Override
public List<Department> select() {
List<Department> result = null;
// 'department' 테이블에 데이터를 갱신하기 위한 SQL의 템플릿
String sql = "SELECT deptno, dname, loc FROM department";
/** SQL 구문 실행하기 위한 객체 */
// --> import java.sql.PreparedStatement;
PreparedStatement pstmt = null;
// --> import java.sql.ResultSet;
ResultSet rs = null;
try {
// pstmt 객체 할당
pstmt = conn.prepareStatement(sql);
// SELECT 구문을 실행한 후, 결과셋을 리턴받는다.
rs = pstmt.executeQuery();
/** SQL 결과를 컬렉션에 할당*/
// SQL이 실행되므로 컬렉션을 할당한다.
result = new ArrayList<Department>();
// 한 줄씩 스캔하는 반복문 구성
while (rs.next()) {
int deptno = rs.getInt("deptno");
String dname = rs.getString("dname");
String loc = rs.getString("loc");
Department item = new Department(deptno, dname, loc);
result.add(item);
}
} catch (SQLException e) {
System.out.println("MySQL SQL Fail : " + e.getMessage());
} finally {
// 객체를 생성한 순서의 역순으로 객체를 닫는다.
if ( rs != null) {
try {
rs.close();
} catch (SQLException e) { }
}
if ( pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) { }
}
}
return result;
}
}
- Insert
public class Main01 {
public static void main(String[] args) {
// 1) 데이터베이스 접속
// --> import java.sql.Connection;
// --> import study.java.helper.DBHelper;
Connection conn = DBHelper.getInstance().open();
if (conn == null) {
System.out.println("데이터베이스 접속 실패");
return;
}
// 2) INSERT를 수행할 데이터 생성
// --> 사용되지 않는 값(deptno)는 0(int)이나 null(String)로 지정한다.
Department model = new Department(0, "인터넷통신", "공학관");
// 3) 데이터 저장
DepartmentDao dao = new DepartmentDaoImpl(conn);
int result = dao.insert(model);
// 4) 결과 판별
System.out.println(result+ "번 데이터 저장됨");
// 5) DB 접속 해제
DBHelper.getInstance().close();
}
}
- Delete
public class Main02 {
public static void main(String[] args) {
// 1) 데이터베이스 접속
Connection conn = DBHelper.getInstance().open();
if ( conn == null) {
System.out.println("데이터베이스 접속 실패");
return;
}
// 2) 삭제할 데이터
// --> Main01에서 출력된 값을 입력하세요.
int target = 207;
// 3) 501번 데이터 삭제
DepartmentDao dao = new DepartmentDaoImpl(conn);
int result = dao.delete(target);
// 결과 판별
System.out.println(result + "개의 데이터 삭제됨");
DBHelper.getInstance().close();
}
}
- Update
public class Main03 {
public static void main(String[] args) {
// 1) 데이터베이스 접속
Connection conn = DBHelper.getInstance().open();
if (conn == null) {
System.out.println("데이터베이스 접속 실패");
return;
}
// 2) UPDATE를 수행할 데이터 생성
Department model = new Department(102, "인터넷통신학과", "7호관");
// 3) 데이터 수정
DepartmentDao dao = new DepartmentDaoImpl(conn);
int result = dao.update(model);
// 4) 결과 판별
System.out.println(result + "개의 데이터 수정됨");
// 5) DB 접속 해제
DBHelper.getInstance().close();
}
}
- Selectone
public class Main04 {
public static void main(String[] args) {
// 1) 데이터베이스 접속
Connection conn = DBHelper.getInstance().open();
if (conn == null) {
System.out.println("데이터베이스 접속 실패");
return;
}
// 2) 조회할 데이터
int target = 101;
// 3) 데이터 수정
DepartmentDao dao = new DepartmentDaoImpl(conn);
Department result = dao.selectOne(target);
// 4) 결과 판별
if (result == null) {
System.out.println("조회결과 없음");
} else {
System.out.println(result.toString());
}
// 5) DB 접속 해제
DBHelper.getInstance().close();
}
}
- Select
public class Main05 {
public static void main(String[] args) {
// 1) 데이터베이스 접속
Connection conn = DBHelper.getInstance().open();
if (conn == null) {
System.out.println("데이터베이스 접속 실패");
return;
}
// 2) 데이터 목록 조회
DepartmentDao dao = new DepartmentDaoImpl(conn);
List<Department> result = dao.select();
// 3) 결과 판별
if (result == null) {
System.out.println("조회결과 없음");
} else {
for (int i = 0; i < result.size(); i++) {
Department item = result.get(i);
System.out.println(item.toString());
}
}
// 4) DB 접속 해제
DBHelper.getInstance().close();
}
}
결론
- Interface를 만드는 이유
- 자신이 원하는 기능을 분류하기 위하여 인터페이스를 정의
- 즉, 인터페이스는 구현하고자 하는 기능에 대한 설계도.
- 데이터베이스 = 자료를 저장하기 위한 저장소
- 자료는 내용의 주제에 따라서 테이블이라는 공간에 저장,수정,삭제,조회 된다.
- 즉, INSERT, UPDATE, DELETE, SELECT가 수행된다.
- JavaBeans의 역할
- 하나의 테이블(주제)를 표현하고 실제 데이터를 저장한다.
- 프로그램 안에서 데이터를 전달하는 역할을 하기 때문에 DTO(Data Transfer Object)라고 부르기도 한다.
- DAO 패턴
- 하나의 테이블 안에서 이루어지는 INSERT, UPDATE, DELETE, SELECT 처리를 Java언어로 표현하기 위한 구현 패턴.
- 패턴이라 함은 구현을 위한 순서가 정해져 있다는 의미.
- 즉, Impl 클래스의 구현 과정을 잘 파악해 두는 것이 중요한다.