우아한 테크코스/테크코스

[Java] JDBC / 데이터 액세스 레이어 / DAO

jamie. 2020. 2. 23. 16:17
반응형

용어

 JDBC : Java DataBase Connectivity; 약칭이 아닌 정식 명칭

 API : Application Programming Interface : 운영체제나 프로그래밍 언어가 준비한 라이브러리를 애플리케이션에서 이용하기 위한 입구가 되는 것, Java의 경우 표준으로 준비된 각종 클래스가 API

JDBC

 자바에서는 DB에 접속하기 위한 API로 JDBC가 준비되어 있음

레이어를 나누지 않았을 때의 순서

1. 데이터 소스 획득

 웹 애플리케이션에서는 일반적으로 DB와의 연결을 애플리케이션 서버가 관리

> 웹 애플리케이션이 어떻게 DB에 연결하는지 일일히 신경쓰지 않아도 됨

 웹 애플리케이션이 DB에 접근하려면 먼저 JNDI(Java Namming and Directory Interface)라는 API를 이용해 애플리케이션 서버에서 DataSource 클래스의 객체를 구해야 함

 DataSource : DB에 대한 접속을 구하기 위한 객체

2. 연결 획득

 DataSource를 구하는데 성공했다면 getConnection 메서드를 호출해 DB에 연결 - SQL을 실행할 준비

 DB에 대한 연결은 COnnection 클래스의 객체로 표현

3. SQL의 실행

 SQL을 실행하려면 Connection 객체의 createStatement 메서드를 호출해 Statement 객체를 구함

 인수에 SQL문을 지정해 Statement 객체의 executeQuery 메서드를 호출함으로써 SQL을 실행

4. SQL 실행 결과의 취득

 SQL의 실행 결과는 executeQuery 메서드의 반환값으로 얻을 수 있는 ResultSet 객체로부터 구할 수 있음

 ResultSet 객체 : next 메서드로 레코드를 호출하고 인수에 칼럼명을 지정해 getString / getInt 등 반환값의 형태로 메서드를 호출해 각 칼럼의 값을 꺼낼 수 있음

레이어를 나누지 않았을 때의 예제

public class ProductLogic {
    public List<ProductItem> getProductList() {
        List<ProductItem> result = new ArrayList<ProductItem>();
        
        InitialContext ic;
        Connection conn = null;
        Statement stmt = null;
        Result rs = null;
        
        try {
            // 1. 데이터 소스 획득
            ic = new InitialContext();
            DataSource ds = (DataSource) ic.lookup("java:comp/env/jdbc/pentominoDB");
            
            // 2. 연결 획득
            conn = ds.getConnection();
            
            // 3. SQL 실행 - SELECT
            stmt = conn.createStatement();
            rs = stmt.executeQuery("select * from PRODUCT_ITEM");
            
            // 4. SQL 결과를 ProductItem에 담음
            while (rs.next()) {
                String itemId = rs.getString("ITEM_ID");
                String itemName = rs.getString("ITEM_NAME");
                Integer price = rs.getInt("PRICE");
                
                result.add(new ProductItem(itemId, itemName, price));
            }
        } catch (NamingException ex) {
            throw new AppException(ex);
        } catch (SQLException ex) {
            throw new AppException(ex);
        // 뒷정리 및 에러가 발생했을 때의 처리
        } finally {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException ex) {
                    // Do nothing.
                }
            }
            
            if (stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException ex) {
                    // Do nothing.
                }
            }
            
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException ex) {
                    // Do nothing.
                }
            }
        }
        
        return result;
    }
}

레이어를 나누지 않았을 때의 단점

 테이블에서 레코드를 취득하는 데 상당히 번거로운 코드를 작성해야 함

 생각 없이 비즈니스 로직을 작성하면 소스 코드의 유지보수성 및 가독성이 크게 저하됨

 그렇기 때문에 비즈니스 로직 레이어와 데이터 액세스 레이어의 분리가 필요

DAO 패턴을 이용한 데이터 액세스 레이어의 구현

 구체적으로 데이터 액세스 레이어를 구현하려면 DAO(Data Acess Object; 이하 다오)를 이용. DAO는 J2EE의 디자인 패턴 중 하나로, DB에 대한 연결 기능을 DAO라는 객체로 분리해 재사용성과 유지보수성을 향상시킨 것

예제

 ProductItemDao - 모든 레코드를 취득하는 selectAll 메서드를 가지고 있음

public interface ProductItemDao {
    /**
     * 상품 목록을 가져온다.<br />
     *
     * @return 상품의 목록
     */
    public List<ProductItem> selectAll() throws SQLException;
}

 보통 DAO는 데이터베이스의 테이블별로 작성, 테이블에 대한 CRUD 처리를 각각 메서드로 구현하는 것이 일반적

 DAO에 준비되는 CRUD 처리에 대응하는 메서드의 예 - 그 외 준비할만한 것들

    // 상품 ID를 키로 상품 검색
    public ProductItem selectByItemId(String itemId);
    
    // 인수로 전달된 상품 정보를 삽입
    public int insert(ProductItem productItem);
    
    // 인수로 전달된 상품 정보를 갱신
    public int update(ProductItem productItem);
    
    // 인수로 전달된 상품 정보를 삭제
    public int delete(ProductItem productItem);

 위 예 외에도 비즈니스 로직의 요구에 맞춰 복잡한 문의나 갱신을 실시하는 메서드를 자유롭게 추가할 수 있음

 DAO의 역할 - "DB 접속을 은폐하는 것" : 어떤 처리 내역을 추가하느냐는 개발자의 자유

 ProductLogic 클래스의 getProductList를 ProductItemDao를 이용하도록 고치면 아래와 같음

public List<ProductItem> getProductList() {
    // DAO 취득
    ProductItemDao productItemDao = new ProductItemDaoImpl();
    
    // 상품 정보 목록 취득
    List<ProductItem> result;
    try {
        result = productItemDao.selectAll();
    } catch (SQLException ex) {
        throw new AppException(ex);
    }
    
    return result;
}

장점

 JDBC를 이용한 DB 연결을 DAO로 분리한 것 뿐이므로 예제로만은 효용성이 별로 느껴지지 않을 수 있음

 취득한 ProductItem의 리스트에 별도로 작업을 하는 비즈니스 로직이 추가되는 경우, 번거로운 DB 연결이 DAO로 분리되었기 때문에 코드 전체가 깔끔해져서 가독성이 좋아진다

반응형