토비의 스프링-DAO-(1)

Song_MinGyu·2021년 7월 20일
0

Spring 정리

목록 보기
1/10
post-thumbnail

DAO

  • Data Access Object는 DB를 사용해 데이터를 조회하거나 조작하는 기능을 전담하도록 만든 오브젝트

Incorrect UserDao

public class UserDao {
    public void add(user user) throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.jdbc.Driver");
        Connection c = DriverManager.getConnection("jdbc:mysql://localhost/usersDB","ID","PASSWORD");
        PreparedStatement ps = c.prepareStatement("insert into users(id,name,password)values(?,?,?)");
        ps.setString(1,user.getId());
        ps.setString(2,user.getName());
        ps.setString(3,user.getPassword());

        ps.executeUpdate();

        ps.close();
        c.close();
    }
    
    public User get(String id) throws ClassNotFoundException,SQLException {
        Class.forName("com.mysql.jdbc.Driver");
        Connection c = DriverManager.getConnection("jdbc:mysql://localhost/usersDB","ID","PASSWORD");
        PreparedStatement ps = c.prepareStatment("select * from users where id = ?");
        ps.setString(1,id);

        ResultSet rs = ps.executeQuery();
        rs.next();
        User user = new User();
        user.setId(rs.getString("id"));
        user.setName(rs.getString("name"));
        user.setPassword(rs.getString("password"));

        rs.close();
        ps.close();
        c.close();

        return user;
    }
}

CODE 분석

  • DriverManager
    • JDBC Driver 세트를 관리하기 위한 기본 서비스
    • getConnection(String url) Method --> 주어진 데이터베이스 URL에 대한 연결 설정을 시도
    • 공식 문서 DOC
  • PreparedStatement interface
    • Statement class 확장
    • 사전 컴파일된 SQL문을 나타내는 객체, 해당 객체는 여러번 반복하여 사용이 가능함
    • setString(int parameterIndex, String x) Method --> 지정된 매개 변수를 주어진 string 값으로 설정
    • 공식 문서 DOC
  • Connection interface
    • 특정 데이터베이스와의 연결, SQL문이 실행되고 연결 내용 내에서 결과 반환
    • Connection.prepareStatement(SQL String)
      • 매개변수가 있는 SQL문을 데이터베이스로 보내기 위한 개체를 만든다.
      • 매개변수 --> "?"이 포함 할 수 있는 SQL String
      • Return --> PreparedStatement 객체로 반환
    • 공식 문서 DOC
  • ResultSet class
    • 일반적으로 데이터베이스 쿼리문 실행하여 생성되는 결과 집합을 나타내는 데이터 테이블
    • 공식 문서 DOC
  • Class.forName(String className)
    • Class로더를 사용하여 주어진 문자열 이름을 가진 클래스 또는 인터페이스와 관련된 객체를 반환한다.

문제점

  • 변화 대응 불가능
  • 분리 필요

커넥션 만들기의 추출

  1. 중복 코드 메소드 추출
public class UserDao {
    public void add(user user) throws ClassNotFoundException, SQLException {
        Connection c = getConnection();
        PreparedStatement ps = c.prepareStatement("insert into users(id,name,password)values(?,?,?)");
        ps.setString(1,user.getId());
        ps.setString(2,user.getName());
        ps.setString(3,user.getPassword());

        ps.executeUpdate();

        ps.close();
        c.close();
    }
    
    public User get(String id) throws ClassNotFoundException,SQLException {
        Connection c = getConnection();
        PreparedStatement ps = c.prepareStatment("select * from users where id = ?");
        ps.setString(1,id);

        ResultSet rs = ps.executeQuery();
        rs.next();
        User user = new User();
        user.setId(rs.getString("id"));
        user.setName(rs.getString("name"));
        user.setPassword(rs.getString("password"));

        rs.close();
        ps.close();
        c.close();

        return user;
    }

    private Connection getConnection() throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.jdbc.Driver");
        Connection c = DriverManager.getConnection("jdbc:mysql://localhost/usersDB","ID","PASSWORD");
        return c;
    }
}
  • 중복 코드 분리, 해당 내용이 독립적이므로 수정도 간단해졌다.
  • 하지만 해당 DAO가 각기 다른 드라이버를 사용해야하는 경우 소스코드 내부를 수정해야하는 문제점 발생

상속을 통한 확장

  • DB 커넥션은 완성했지만, 여러 종류의 DB 커넥션을 연결하기에는 일일이 수정해줘야 한다.
  • 코드를 한 단계 더 분리하여 완성한다.
  • 추상 메소드로 만들어서 사용
public abstract class UserDao {
    public void add(user user) throws ClassNotFoundException, SQLException {
        Connection c = getConnection();
        PreparedStatement ps = c.prepareStatement("insert into users(id,name,password)values(?,?,?)");
        ps.setString(1,user.getId());
        ps.setString(2,user.getName());
        ps.setString(3,user.getPassword());

        ps.executeUpdate();

        ps.close();
        c.close();
    }
    
    public User get(String id) throws ClassNotFoundException,SQLException {
        Connection c = getConnection();
        PreparedStatement ps = c.prepareStatment("select * from users where id = ?");
        ps.setString(1,id);

        ResultSet rs = ps.executeQuery();
        rs.next();
        User user = new User();
        user.setId(rs.getString("id"));
        user.setName(rs.getString("name"));
        user.setPassword(rs.getString("password"));

        rs.close();
        ps.close();
        c.close();

        return user;
    }
    public abstract Connection getConnection() throws ClassNotFoundException, SQLException;
}
public class MysqlDao extends UserDao {
    public Connection getConnection() throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.jdbc.Driver");
        Connection c = DriverManager.getConnection("jdbc:mysql://localhost/usersDB","ID","PASSWORD");
        return c;
    }
}
public class MariadbDao extends UserDao {
    public Connection getConnection() throws ClassNotFoundException, SQLException {
        Class.forName("org.mariadb.jdbc.Driver");
        Connection c = DriverManager.getConnection("jdbc:mariadb://localhost/userDB","ID","PASSWORD");
        return c;
    }
}
  • 이렇게 수정함으로써 UserDao의 클래스는 수정할 필요 없이 다른 데이터베이스 드라이버를 추가할 수 있게 되었다.
  • 이렇게 슈퍼클래스에 기본적인 로직의 흐름을 만들고 그 기능의 일부를 추상 메소드나 오버라이딩이 가능하게 한 후 서브클래스에서 구현하는 방법을 템플릿 메소드 패턴이라고 한다.
  • 상속을 많이 사용한다는 단점이 있다.
    • 만약 UserDao가 다른 목적을 위해 상속을 사용하고 있다면? --> Java는 다중 상속을 허용하지 않는다.
    • 상속의 긴밀한 결합을 허용하기 때문에 슈퍼클래스의 메소드를 사용할 수 있다.
    • 다른 DAO 적용 불가
profile
Always try to Change and Keep this mind

0개의 댓글