JDBC와 DAO패턴

#JAVA_023
Jan 25, 2024
JDBC와 DAO패턴
 

🍉 개요

이 블로그에서는 현대 웹 개발의 핵심 개념들을 많이 다루어 보고자 한다. 데이터 베이스 관리, DAO (Data Access Object)패턴, CRUD (Create, Read, Update, Delete)작업 등의 지식은 모든 웹 개발자들에게 필수지식이라고 할 수 있다. JDBC가 어떻게 HTTP 프로토콜 기반으로 상호작용하는지 간단한 은행 시스템을 구현하면서 알아보도록 하겠다.
 
JDBC와 데이터베이스의 통신구조
notion image
 

🍊 데이터 베이스 연결

데이터 베이스 연결은 모든 데이터 기반 애플리케이션의 필수적인 부분이다. 그리고 SRP의 원칙에 따라서 서버와의 연결 업무를 주로 담당할 DBConnection 클래스를 만든다. 이 클래스는 MariaDB 데이터 베이스에 연결하기 위한 필수 정보와 로직을 구현한다.
public class DBConnection { public static Connection getInstance() { String username = "root"; String password = "1234"; String url = "jdbc:mariadb://localhost:3306/cosdb"; // 프로토콜이 적용된 소켓 try { Connection conn = DriverManager.getConnection(url, username, password); System.out.println("db connect success"); return conn; } catch (Exception e) { e.printStackTrace(); } return null; } }
 
 
사실 JDBC와 통신 구조에 대해서 자세하게 설명한 글이 있으므로, 연결에 대해 더 자세하게 알고 싶으시다면은 아래 게시글도 한 번 참고해주시길 바란다.
 
 

🥭 비즈니스와 데이터 관리 로직 분리

많은 업체들이 데이터 베이스와 상호작용 하면서 SRP(Single Responsibility Principle) 단일 책임 원칙에 따라 시스템을 구축하고자 한다. 그렇게 구축을 하게 되면 시스템 코드와 데이터 베이스 코드가 더 명확해지고 간결해지며 가독성이 높아져 유지보수가 쉬워지고 그리고 향후에 비슷한 업무가 있을 때 그 코드 로직을 재사용할 수 있다는 이점이 있다. 그리고 어디가 문제가 발생했을 때, 해당 업무에 대한 책임을 가지고 있는 코드를 집중해서 보수하면 되므로, 더 효율적인 업무가 가능하다.
 
그러한 업무의 일환으로 많은 기업들은 DAO(Data Access Object)패턴을 사용한다.
 

✏️DAO(Data Access Object) 패턴이란??

DAO는 데이터를 관리하는 데 자주 사용되기 때문에 패턴으로서 자리잡은 하나의 시스템 구축 방법이다. 흔히 데이터 접근 로직과 비즈니스 로직을 분리하기 위해서 주로 사용된다.
 
DAO패턴에서는 직접적으로 데이터와 소통해야되기 때문에, 쿼리를 다루는 코드들 CRUD (Create, Read, Update, Delete) 메소드가 반드시 구현이 되어야 한다. .
 
DAO의 기본 구조
public class BankDAO { public int deleteByNumber(){ // Delete 로직 } public int insert(){ // Create 로직 } public int updateByNumber(){ // Update 로직 } public selectByNumber(){ // Read 로직 } public selectAll(){ // Read 로직 } }
 
여기서 모든 구조를 구현하면 가독성이 떨어지므로, insert메소드 로직을 한번 살펴보자.
 
Insert 메소드의 구조
public int insert(String password, int balance){ Connection conn = DBConnection.getInstance(); try { String sql = "insert into account_tb(password, balance, created_at) values(?, ?, now())"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setString(1, password); pstmt.setInt(2, balance); int num = pstmt.executeUpdate(); return num; } catch (Exception e) { e.printStackTrace(); } return -1; }
notion image
  • pstmt.excuteUpdate는 정수로 해당 쿼리의 결과를 나타내므로 int를 반환 받을 수 있게 설정
  • insert로 자료를 입력하고자 하므로, passwordbalance를 매개변수로 받고 있다.
  • Connection 객체를 DBConnection으로부터 호출한다. (생성이 아니라 재사용)
 
 
notion image
  • MariaDB와 상호작용하기 때문에 MariaDB 쿼리를 작성해야 된다. 여기에 사용되는 데이터 입력 함수형태는 아래와 같다.
    • ‘insert into 테이블명( 속성 요소1, 속성 요소2) values (입력값, 입력값);
  • PreparedStatement 클래스는 JDBC에서 버퍼로서 사용되는 클래스이다. 여기에 쿼리를 담아서 보낸다.
 
 
notion image
  • setStringsetInt 뒤 괄호는PreparedStatement 에 사용된 쿼리에 변수값을 직접 지정해주는 코드이다.
  • 실제 쿼리는 .excuteUpdate()코드로 전송이 되어 답변을 정수로 받는다.
 
 
일단 insert메소드만 자세하게 분석하였지만, 실제로는 아까 말했듯이 DAO는 CRUD에 대한 모든 메소드를 구현하여 DB와 상호작용 해야된다. 실제 코드는 아래에 남겨둘테니 한 번 각 메소드의 구조를 참고하시면 좋을 것 같다.
/** * DAO - Data Access Object * SRP - 단일책임의 원칙 */ public class BankDAO { public int deleteByNumber(int number){ Connection conn = DBConnection.getInstance(); try { String sql = "delete from account_tb where number = ?"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setInt(1, number); int num = pstmt.executeUpdate(); return num; } catch (Exception e) { e.printStackTrace(); } return -1; } public int insert(String password, int balance){ Connection conn = DBConnection.getInstance(); try { String sql = "insert into account_tb(password, balance, created_at) values(?, ?, now())"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setString(1, password); pstmt.setInt(2, balance); int num = pstmt.executeUpdate(); return num; } catch (Exception e) { e.printStackTrace(); } return -1; } public int updateByNumber(int balance, int number){ Connection conn = DBConnection.getInstance(); try { String sql = "update account_tb set balance = ? where number = ?"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setInt(1, balance); pstmt.setInt(2, number); int num = pstmt.executeUpdate(); return num; } catch (Exception e) { e.printStackTrace(); } return -1; } public Account selectByNumber(int number){ Connection conn = DBConnection.getInstance(); try { String sql = "select * from account_tb where number = ?"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setInt(1, number); ResultSet rs = pstmt.executeQuery(); if(rs.next()){ // 커서 한칸 내리기 Account account = new Account( rs.getInt("number"), rs.getString("password"), rs.getInt("balance"), rs.getTimestamp("created_at") ); return account; } }catch (Exception e){ e.printStackTrace(); } return null; } public List<Account> selectAll(){ Connection conn = DBConnection.getInstance(); try { String sql = "select * from account_tb order by number desc"; PreparedStatement pstmt = conn.prepareStatement(sql); ResultSet rs = pstmt.executeQuery(); List<Account> accountList = new ArrayList<>(); while(rs.next()){ Account account = new Account( rs.getInt("number"), rs.getString("password"), rs.getInt("balance"), rs.getTimestamp("created_at") ); accountList.add(account); } return accountList; }catch (Exception e){ e.printStackTrace(); } return null; } }
 
 
 
Share article
RSSPowered by inblog