연동에 대해서 진행 하기 전 꼭! 알고 가면 좋을 것 같은 사항을 정리해서 아래에 적어뒀다. 아래의 내용을 읽고도 어려운 부분이 있으면 정리를 한 번 쭉 읽어보고 다시 진행하는 것도 좋은 방법이라 생각한다! 어렵게 생각하기 보다는 통신이 어떻게 진행 되는지 자바와 DBMS가 어떻게 흘러가는지 흐름을 파악 하는 것이 공부에 더욱 도움이 될 것이라 생각이 된다!
하기 전! 꼭 알고 가자!
- “INSERT”, “UPDATE”, “DELETE“ 는 요청하면 영향 받은 행이 리턴 된다.
- “SELECT” 는 요청하면 테이블이 리턴 된다.
- 프로그램은 언어를 자신의 언어로 바꿔야 한다.
- “DB”는 “JAVA”에게 넘길 때 “JSON”으로 바꿔 넘기고 “JAVA”는 그것을 “오브젝트”로 바꾼다.
- 통신은 무조건 “String”으로 온다.
JDBC 폴더 구성과 설명
- JDBC의 “java” 폴더 구성은 “DAO”, “DB”, “MODEL”로 나눠 진다. → DAO : 데이터 조회 및 조작 / DB : 데이터베이스 연결 및 설정 / MODEL : 모델 클래스 저장
- 또한 “TEST” 폴더도 있는데 java 폴더와 구성은 똑같다. → 여기서는 “TDD”를 기반으로 우리는 진행 할 것이다.
- TEST 폴더는 java 폴더에서 만든 코드를 똑같이 만들지만 “제이유닛(JUnit)”을 사용하여 기능을 테스트하는 용도로 사용한다.
TDD(test-driven development, 테스트 주도 개발)란?
한 마디로 선 테스트 후 개발 이라 알면 된다. 다음에 조금 더 자세히 알아보자!
JDBC 실습 진행
JAVA 폴더 gradle 추가
- 필요한 라이브러리를 직접 gradle에 추가 해준다. → “lombok”과 “mariadb.jdbc”를 추가 하였다.
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 생성
- 연동할 DB와 Table을 생성하는 Query문을 작성한다.
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의 연동
- Test 폴더를 활용하여 Connection이 제대로 진행 되었는지 파악한다.
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("성공"); } } }
출력 결과
이때 TEST 폴더의 특징에 대해서 알 수 있다.
1. 리턴타입을 적을 수 없다. (void 타입만 사용 가능)
2. 매개변수를 적을 수 없다.
3. @Test 붙이면 메서드 별로 실행 가능하다.
4. java 파일명 끝에 “Test”를 붙힌다. (컨벤션)
5. class 명 끝에 “_test”를 붙힌다. (컨벤션)
또한 자세히 보면 TEST 코드의 흐름이 “given”, “when”, “then” 순으로 진행 된다고 표시 되어 있는데 이는 “파라미터”, “본 코드”, “검증” 순으로 가독성이 좋도록 표기한 것이다.
- TEST 코드가 정상적으로 진행 되는 것을 확인 후 java 폴더에 만들어 주고 코드를 필요에 따라 수정 후 연결 코드를 완성한다.
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 모델 클래스 생성
- 연동할 데이터베이스의 테이블을 참고하여 모델 클래스를 만들어 준다.
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를 버퍼에 담아 전송
- Query문 마다 class를 생성해주고 그에 맞는 Query를 버퍼에 담아 전송해준다.
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문 별 차이와 특징에 대해서 분명하게 파악하고 이해한 후 넘어가자!
- 작성한 DAO를 TEST를 진행한다.
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 문 출력 결과
코드 출력
TABLE 출력
UPDATE 문 출력 결과
코드 출력
TABLE 출력
DELETE 문 출력 결과
코드 출력
TABLE 출력
SELETE 문 (단일) 출력 결과
코드 출력
SELETE 문 (다중) 출력 결과
코드 출력
생각
위와 같이 간단하게 JDBC를 실습 할 수 있는데 처음에 들어오기 전 말했던 것처럼 코드 자체를 파악하기 보다는 JDBC의 흐름에 대해서 파악하면 더욱 쉽게 다가올 것이라 느껴진다. 도저히 이해가 안되면 앞의 내용을 살펴 보거나 구글링을 해보는 것을 추천한다!
Share article