DAO Pattern이란? 

▶ 업무와 DBMS를 분리하기 위해 사용됩니다. 업무와 데이터 2계층을 분리하고, 서로 그 상태를 동일하게 유지(persistence) 할 수 있습니다.

 

 

먼저 jdbc를 사용하기 위한 라이브러리를 추가하겠습니다. 아래 링크에서 다운로드 하시면 됩니다.

https://github.com/xerial/sqlite-jdbc/releases 

 

Releases · xerial/sqlite-jdbc

SQLite JDBC Driver. Contribute to xerial/sqlite-jdbc development by creating an account on GitHub.

github.com

파일을 다운로드하고 import하기 편한 위치에 저장하시면 됩니다.

1. Libaries 추가 intellij 기준입니다.  File -> Project Structure -> '+' 위에 파일을 추가해주고 ok를 눌러줍니다.

 


코드요약: 학생은 학교 사이트에 가입합니다. 이때 primary key는 DB에서 자동적으로 생성 증가하며, 학생은 이름과 나이만 입력합니다.

 

클래스 다이어그램과 코드를 살펴보겠습니다.

 

 

1. SchoolDAOImpl class -> interface를 이용해서 상속한 이유는 여러가지 DB를 사용할 수 있기 때문에 유연성을 위해서 오버라이딩합니다. 

import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class SchoolDAOImpl implements SchoolDAO{
private Connection connection;
private Statement statement;
private String DBName;
private String tableName;
private ResultSet rs;
public SchoolDAOImpl(String DBName, String tableName) throws SQLException {
this.DBName = DBName;
this.tableName = tableName;
connection= DriverManager.getConnection("jdbc:sqlite:"+DBName);
statement=connection.createStatement();
statement.executeUpdate("DROP TABLE IF EXISTS "+ tableName);
statement.executeUpdate("CREATE TABLE "+ tableName+" (ID INTEGER PRIMARY KEY AUTOINCREMENT, name text, age INTEGER)");
System.out.println(tableName+" 생성완료");
}
@Override
public void insert(Student student) throws SQLException {
String fmt = "INSERT INTO %s VALUES(%d ,'%s', %d)";
String query = String.format(fmt, tableName, student.getId(),student.getName(), student.getAge());
statement.execute(query);
}
@Override
public List<Student> findAll() {
ArrayList<Student> students = new ArrayList<Student>();
try {
rs = statement.executeQuery("SELECT * FROM " +
tableName);
while (rs.next()) {
students.add(new Student(rs.getInt("id"),
rs.getString("name"), rs.getInt("age")));
}
}
catch (SQLException e) { e.printStackTrace(); }
return students;
}
@Override
public Student findById(int id) {
Student student = null;
try {
String fmt = "SELECT * FROM %s WHERE id = %d";
String q = String.format(fmt, tableName, id);
rs = statement.executeQuery(q);
if (rs.next()) {
student = new Student(rs.getInt("id"),
rs.getString("name"), rs.getInt("age"));
}
}
catch (SQLException e) { e.printStackTrace(); }
return student;
}
@Override
public void update(int id, Student student) {
Student result = findById(id);
if (result != null) {
try {
String fmt = "UPDATE %s SET name = '%s' WHERE id = %d";
String q = String.format(fmt, tableName,
student.getName(),student.getId());
statement.execute(q);
}
catch (SQLException e) { e.printStackTrace(); }
}
}
@Override
public void delete(int id) {
try {
String fmt = "DELETE FROM %s WHERE id = %d";
String q = String.format(fmt, tableName, id);
statement.execute(q);
}
catch (SQLException e) { e.printStackTrace(); }
}
@Override
public void delete(Student p) {
delete(p.getId());
}
}

Connection 인터페이스

  • 자바 응용 프로그램과 데이터베이스를 연결한 세션 유지및 쿼리 실행합니다.
  • 쿼리를 실행시킬 수 있는 Statement나 PreparedStatement 등을 생성하는 Factory입니다.
  • createStatement(): SQL 쿼리를 실행시킬 수 있는 Statement 인터페이스 객체를 생성합니다. 

Statement 인터페이스

  • SQL 쿼리를 데이터베이스에서 실행합니다.
  • SELECT 쿼리를 실행시킬 때 ResultSet 인터페이스 객체를 생성하는 Factory입니다. 
  • executeQuery(String sql): SELECT 쿼리를 실행하고 ResultSet 객체를 반환
  • executeUpdate(String sql): 주어진 sql 쿼리를 실행
  • create, drop, insert, update, delete 등 실행 가능

ResultSet 인터페이스 

  • 테이블의 한 행(row)를 가리키는 커서(cursor)입니다. 
  • 커서는 첫 번째 행 이전을 가리킵니다. ->  next()를 이용해서 데이터가 실제 있는지 확인해야 합니다.
  • next(): 현재 위치에서 커서를 다음 행으로 이동(true/false 반환)
  • getInt(int columnIndex), getInt(String columnName): 주어진 컬럼의 데이터를 정수 형태로 반환
  • getString(int columnIndex), getString(String columnName): 주어진 컬럼의 데이터를 문자열 형태로 반환

 

2. Student class

public class Student {
private Integer id;
private String name;
private Integer age;
public Student(Integer id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
}

 

3. Main class

import java.sql.SQLException;
import java.util.List;
public class Main {
public static void main(String[] args) throws SQLException {
SchoolDAO schoolDAO = new SchoolDAOImpl("school.db", "student");
// 학생 2명 추가
schoolDAO.insert(new Student(1,"kim",10));
schoolDAO.insert(new Student(2,"lee",13));
// 학생 전체 출력
List<Student> result = schoolDAO.findAll();
for (Student student1: result){
System.out.println(student1.getId()+" "+student1.getName()+" "+student1.getAge());
}
// id가 1인 학생 찾기
Student student = schoolDAO.findById(1);
System.out.println(student.getId()+" "+student.getName()+" "+student.getAge());
// id가 1인 학생의 이름 변경
schoolDAO.update(1, new Student(1, "park",10));
// id가 1인 학생이 바꼈는지 확인
student = schoolDAO.findById(1);
System.out.println(student.getId()+" "+student.getName()+" "+student.getAge());
// id가 2인 학생 삭제
schoolDAO.delete(2);
// 학생 전체 출력
result = schoolDAO.findAll();
for (Student student1: result){
System.out.println(student.getId()+" "+student.getName()+" "+student.getAge());
}
}
}

원하는 바와 같이 출력되는 것을 볼 수 있습니다. 

 

 

지금까지 업무와 데이터 2계층을 분리하고, 서로 그 상태를 동일하게 유지하는 DAO Pattern을 알아봤습니다. 감사합니다.

전체 코드는 아래에서 확인 가능합니다:)

https://github.com/rlaehdals/design-pattern

 

GitHub - rlaehdals/design-pattern

Contribute to rlaehdals/design-pattern development by creating an account on GitHub.

github.com