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