64_JDBC 연동

Jan 26, 2024
64_JDBC 연동
연동에 대해서 진행 하기 전 꼭! 알고 가면 좋을 것 같은 사항을 정리해서 아래에 적어뒀다. 아래의 내용을 읽고도 어려운 부분이 있으면 정리를 한 번 쭉 읽어보고 다시 진행하는 것도 좋은 방법이라 생각한다! 어렵게 생각하기 보다는 통신이 어떻게 진행 되는지 자바와 DBMS가 어떻게 흘러가는지 흐름을 파악 하는 것이 공부에 더욱 도움이 될 것이라 생각이 된다!
🌟
하기 전! 꼭 알고 가자!
  1. “INSERT”, “UPDATE”, “DELETE“ 는 요청하면 영향 받은 행이 리턴 된다.
  1. “SELECT” 는 요청하면 테이블이 리턴 된다.
  1. 프로그램은 언어를 자신의 언어로 바꿔야 한다.
  1. “DB”“JAVA”에게 넘길 때 “JSON”으로 바꿔 넘기고 “JAVA”는 그것을 “오브젝트”로 바꾼다.
  1. 통신은 무조건 “String”으로 온다.

JDBC 폴더 구성과 설명

  • JDBC의 “java” 폴더 구성은 “DAO”, “DB”, “MODEL”로 나눠 진다. → DAO : 데이터 조회 및 조작 / DB : 데이터베이스 연결 및 설정 / MODEL : 모델 클래스 저장
  • 또한 “TEST” 폴더도 있는데 java 폴더와 구성은 똑같다. → 여기서는 “TDD”를 기반으로 우리는 진행 할 것이다.
  • TEST 폴더는 java 폴더에서 만든 코드를 똑같이 만들지만 “제이유닛(JUnit)”을 사용하여 기능을 테스트하는 용도로 사용한다.
TDD(test-driven development, 테스트 주도 개발)란? 한 마디로 선 테스트 후 개발 이라 알면 된다. 다음에 조금 더 자세히 알아보자!

JDBC 실습 진행

JAVA 폴더 gradle 추가

  1. 필요한 라이브러리를 직접 gradle에 추가 해준다. → “lombok”“mariadb.jdbc”를 추가 하였다.
    1. dependencies { // https://mvnrepository.com/artifact/org.mariadb.jdbc/mariadb-java-client implementation group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: '3.3.2' // https://mvnrepository.com/artifact/org.projectlombok/lombok compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.18.30' testImplementation platform('org.junit:junit-bom:5.9.1') testImplementation 'org.junit.jupiter:junit-jupiter' }

연동 DB, Table 생성

  1. 연동할 DB와 Table을 생성하는 Query문을 작성한다.
    1. CREATE DATABASE cosdb; CREATE TABLE account_tb( number INT PRIMARY KEY AUTO_INCREMENT, password VARCHAR(100) NOT NULL, balance INT NOT NULL, created_at TIMESTAMP NOT NULL ) ENGINE=INNODB DEFAULT CHARSET=UTF8MB4;

JDBC의 연동

  1. Test 폴더를 활용하여 Connection이 제대로 진행 되었는지 파악한다.
    1. package db; import org.junit.jupiter.api.Test; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DBConnectionTest { @Test // 제이유닛 → 자바로 테스트 할 수 있는 도구 public void getInstance_test(){ // given = 파라미터 // when = 본코드 실행 Connection conn = DBConnection.getInstance(); // then = 눈 검증 if(conn == null){ System.out.println("실패"); } else { System.out.println("성공"); } } }
      출력 결과
      notion image
      이때 TEST 폴더의 특징에 대해서 알 수 있다. 1. 리턴타입을 적을 수 없다. (void 타입만 사용 가능) 2. 매개변수를 적을 수 없다. 3. @Test 붙이면 메서드 별로 실행 가능하다. 4. java 파일명 끝에 “Test”를 붙힌다. (컨벤션) 5. class 명 끝에 “_test”를 붙힌다. (컨벤션) 또한 자세히 보면 TEST 코드의 흐름“given”, “when”, “then” 순으로 진행 된다고 표시 되어 있는데 이는 “파라미터”, “본 코드”, “검증” 순으로 가독성이 좋도록 표기한 것이다.
  1. TEST 코드가 정상적으로 진행 되는 것을 확인 후 java 폴더에 만들어 주고 코드를 필요에 따라 수정 후 연결 코드를 완성한다.
    1. package db; import java.sql.Connection; import java.sql.DriverManager; public class DBConnection { public static Connection getInstance() { String username = "root"; String password = "1234"; // url이란 건 앞에 프로토콜을 적어줘야한다. -> 웹은 http, 파일 서버는 ftp, db는 db마다 다른데 MariaDB는 jdbc:mariadb:// 나머지는 상황에 따라 검색! String url = "jdbc:mariadb://localhost:3306/cosdb"; // 프로토콜이 적용된 소켓 try { Connection conn = DriverManager.getConnection(url, username, password); System.out.println("DB Connection success"); return conn; } catch (Exception e) { e.printStackTrace(); } return null; } }

JDBC 모델 클래스 생성

  1. 연동할 데이터베이스의 테이블을 참고하여 모델 클래스를 만들어 준다.
    1. package model; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; import lombok.ToString; import java.sql.Timestamp; /*** * DB 에 Select 한 데이터를 담기 위한 오브젝트 */ @ToString @AllArgsConstructor @Getter public class Account { private int number; private String password; private int balance; // java.sql의 Timestamp // 카멜표기법 사용하기 private Timestamp createdAt; }
      참고하여 이해하고 제이유닛이 왜 저렇게 들어 갔지는 이해가 안되면 앞의 챕터의 “롬복(lombok)”이 무엇인지 보고 오자!

소켓 생성 후 CRUD에 맞는 Query를 버퍼에 담아 전송

  1. Query문 마다 class를 생성해주고 그에 맞는 Query를 버퍼에 담아 전송해준다.
    1. package dao; import db.DBConnection; import model.Account; import java.awt.*; import java.sql.*; import java.util.*; /*** * DAO - Data Access Object * SRP - 단일책임의 원칙 */ public class BankDAO { // delete 문 (제거) 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; } // 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; } // update 문 (수정) public int updateByNumber(int balance, int number) { // 1. DB 소켓 가져오기 Connection conn = DBConnection.getInstance(); try { // 2. 버퍼에 쿼리 담기 String sql = "update account_tb set balance = ? where number = ?"; // 3. 쿼리 전송 PreparedStatement pstmt = conn.prepareStatement(sql); // 버퍼의 물음표 자리를 채우는 문법 pstmt.setInt(1, balance); pstmt.setInt(2, number); // 4. 리턴 값 가져오기 int num = pstmt.executeUpdate(); return num; } catch (Exception e) { e.printStackTrace(); } return -1; } // select 문 (단일 조회) 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 은 테이블 형태의 데이터 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; } // select 문 (다중 조회) 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 는 커서를 한칸 내려서 읽는 것이다. (이건 아주 중요하다) 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; } }
      INSERT, UPDATE, DELETE는 간단하게 진행이 되어 비슷한 코드를 유지하지만 SELECT는 다르므로 꼭 읽어 봐야한다! Query문 별 차이와 특징에 대해서 분명하게 파악하고 이해한 후 넘어가자!
  1. 작성한 DAO를 TEST를 진행한다.
    1. package dao; import model.Account; import org.junit.jupiter.api.Test; import java.util.List; public class BankDAOTest { @Test public void selectAll_test() { // given // when BankDAO dao = new BankDAO(); List<Account> accountList = dao.selectAll(); //then for (Account a : accountList) { System.out.println(a); } } @Test public void selectByNumber_test() { int number = 5; BankDAO dao = new BankDAO(); Account account = dao.selectByNumber(number); if (account == null) { System.out.println(number + "로 조회된 값이 없습니다"); } else { System.out.println(account); } } @Test public void deleteByNumber_test() { // given int number = 3; // when BankDAO dao = new BankDAO(); int result = dao.deleteByNumber(number); // then if (result == 1) { System.out.println("삭제 성공"); } else if (result == 0) { System.out.println(number + "번호를 찾을 수 없습니다"); } else { System.out.println("삭제 실패"); } } @Test public void insert() { // given String password = "5555"; int balance = 20000; // when BankDAO dao = new BankDAO(); int result = dao.insert(password, balance); //then if (result == 1) { System.out.println("입력 성공"); } else { System.out.println("입력에 실패 하였습니다."); } } @Test public void updateByNumber() { // given int balance = 5000; int number = 3; // when BankDAO dao = new BankDAO(); int result = dao.updateByNumber(balance, number); // then if (result == 1) { System.out.println("수정 성공"); } else if (result == 0) { System.out.println(number + "번호가 없습니다"); } else { System.out.println("수정 실패"); } } }
      INSERT 문 출력 결과
      코드 출력
      notion image
      TABLE 출력
      notion image
      UPDATE 문 출력 결과
      코드 출력
      notion image
      TABLE 출력
      notion image
      DELETE 문 출력 결과
      코드 출력
      notion image
      TABLE 출력
      notion image
      SELETE 문 (단일) 출력 결과
      코드 출력
      notion image
      SELETE 문 (다중) 출력 결과
      코드 출력
      notion image

생각

위와 같이 간단하게 JDBC를 실습 할 수 있는데 처음에 들어오기 전 말했던 것처럼 코드 자체를 파악하기 보다는 JDBC의 흐름에 대해서 파악하면 더욱 쉽게 다가올 것이라 느껴진다. 도저히 이해가 안되면 앞의 내용을 살펴 보거나 구글링을 해보는 것을 추천한다!
Share article
RSSPowered by inblog