풀스택 개발 (Full-Stack Development)/자바프로그래밍

JDBC SQL CRUD 실행객체 Statement PreparedStatement executeQuery executeUpdate DAO 패턴 Scanner

윤슬새벽 2025. 6. 24. 15:11
반응형

✅ 1. 실습 주제

JDBC 프로그래밍의 기본 구조와 SQL 연동을 학습하기 위한 콘솔 기반 CRUD 실습


✅ 2. 학습 목표 및 성과

항목 상세 내용
📌 학습 주제 JDBC를 활용한 자바 콘솔 CRUD 애플리케이션 개발
🎯 학습 성과 DB 연동, SQL 작성, PreparedStatement 적용, 콘솔 입출력 구현
🔐 보안 고려 SQL Injection 방지를 위한 PreparedStatement 사용
💡 고급 기능 ResultSetMetaData 활용 동적 쿼리 실행기(nativeQuery) 구현
🛠 예외 처리 try-catch-finally를 통한 안정적인 DB 자원 관리
 

✅ 3. 구현 기능 요약

기능 설명
insertPhonebook() 연락처 정보 신규 입력
updatePhonebook() ID 기반 연락처 정보 수정
deletePhonebook() ID 기반 연락처 삭제
selectAllPhonebook() 전체 연락처 조회 (정렬된 테이블 출력)
nativeQuery() 사용자가 직접 SQL을 입력하고 결과 확인
 

✅ 4. Java 코드 (PhoneBookDao.java)

package edu.pnu;

import java.sql.*;
import java.util.Scanner;

public class PhoneBookDao {
	private static Scanner sc = new Scanner(System.in);
	private static String url = "jdbc:mysql://localhost:3306/db";

	public static void main(String[] args) throws Exception {
		Connection con = DriverManager.getConnection(url, "user", "*****");
		boolean flag = true;
		while (flag) {
			System.out.print("[I]nsert/[U]pdate/[D]elete/[S]elect/[N]ative/[Q]uit:");
			char c = sc.next().toUpperCase().charAt(0);
			switch (c) {
				case 'I': insertPhonebook(con); break;
				case 'U': updatePhonebook(con); break;
				case 'D': deletePhonebook(con); break;
				case 'S': selectAllPhonebook(con); break;
				case 'N': nativeQuery(con); break;
				case 'Q': flag = false; break;
			}
		}
		System.out.println("Bye~");
	}

	private static void insertPhonebook(Connection con) throws SQLException {
		String name = "홍길동프5";
		String mobile = "010-1234-5678";
		String home = "010-4567-1234";
		String company = "hong com";
		String email = "hong@hong.com";

		String sql = "INSERT INTO phonebook(name, mobile, home, company, email) VALUES (?, ?, ?, ?, ?)";
		PreparedStatement psmt = con.prepareStatement(sql);
		psmt.setString(1, name);
		psmt.setString(2, mobile);
		psmt.setString(3, home);
		psmt.setString(4, company);
		psmt.setString(5, email);

		int cnt = psmt.executeUpdate();
		System.out.println(cnt + "건이 입력되었습니다.");
	}

	private static void updatePhonebook(Connection con) throws SQLException {
		int id = 18;
		String home = "010-4567-1234";
		String company = "hong2 com";
		String email = "hong2@hong.com";

		String sql = "UPDATE phonebook SET home=?, company=?, email=? WHERE id=?";
		PreparedStatement psmt = con.prepareStatement(sql);
		psmt.setString(1, home);
		psmt.setString(2, company);
		psmt.setString(3, email);
		psmt.setInt(4, id);

		int cnt = psmt.executeUpdate();
		System.out.println(cnt + "건이 수정되었습니다.");
	}

	private static void deletePhonebook(Connection con) throws SQLException {
		int id = 15;

		String sql = "DELETE FROM phonebook WHERE id=?";
		PreparedStatement psmt = con.prepareStatement(sql);
		psmt.setInt(1, id);

		int cnt = psmt.executeUpdate();
		System.out.println(cnt + "건이 삭제되었습니다.");
	}

	private static void selectAllPhonebook(Connection con) throws SQLException {
		Statement st = null;
		ResultSet rs = null;

		try {
			st = con.createStatement();
			String sql = "SELECT * FROM phonebook";
			rs = st.executeQuery(sql);

			System.out.println("\n[결과]");
			System.out.printf("%-4s %-8s %-15s %-15s %-15s %-20s\n",
					"ID", "이름", "모바일", "집", "회사", "이메일");

			while (rs.next()) {
				System.out.printf("%-4s %-8s %-15s %-15s %-15s %-20s\n",
						rs.getString("id"),
						rs.getString("name"),
						rs.getString("mobile"),
						rs.getString("home"),
						rs.getString("company"),
						rs.getString("email"));
			}
		} catch (Exception e) {
			System.out.println("SELECT 오류: " + e.getMessage());
		} finally {
			try {
				if (rs != null) rs.close();
				if (st != null) st.close();
			} catch (SQLException e) {
				System.out.println("자원 정리 오류: " + e.getMessage());
			}
		}
	}

	private static void nativeQuery(Connection con) {
		Statement st = null;
		ResultSet rs = null;

		try {
			Scanner sc = new Scanner(System.in);
			System.out.print("실행할 SQL문 입력 (예: SELECT * FROM phonebook): ");
			String sql = sc.nextLine();

			st = con.createStatement();

			if (sql.trim().toUpperCase().startsWith("SELECT")) {
				rs = st.executeQuery(sql);
				ResultSetMetaData meta = rs.getMetaData();
				int colCount = meta.getColumnCount();

				System.out.println("\n[결과]");
				while (rs.next()) {
					for (int i = 1; i <= colCount; i++) {
						System.out.print(rs.getString(i));
						if (i < colCount) System.out.print(" | ");
					}
					System.out.println();
				}
			} else {
				int cnt = st.executeUpdate(sql);
				System.out.println(cnt + "건이 영향을 받았습니다.");
			}
		} catch (Exception e) {
			System.out.println("SQL 실행 오류: " + e.getMessage());
		} finally {
			try {
				if (rs != null) rs.close();
				if (st != null) st.close();
			} catch (SQLException e) {
				System.out.println("자원 정리 오류: " + e.getMessage());
			}
		}
	}
}

✅ 테이블 구조 예시 (MySQL 기준)

CREATE TABLE phonebook (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(50),
  mobile VARCHAR(20),
  home VARCHAR(20),
  company VARCHAR(50),
  email VARCHAR(50)
);

✅ 다음 단계 추천

학습 방향 실습 아이디어
MVC 구조 리팩토링 DAO, DTO 클래스로 분리
사용자 입력 받기 Scanner로 사용자 입력 기반 insert/update
GUI 확장 JavaFX로 화면 기반 전화번호부 만들기
웹 확장 Spring Boot + Thymeleaf 또는 REST API
 

 


🧠 핵심 학습 목표 요약

항목 학습 내용
🔌 JDBC 연결 DriverManager.getConnection()으로 MySQL과 Java 연동
🛠 SQL 실행 방법 Statement vs PreparedStatement 차이 학습
📄 CRUD 구현 Insert / Update / Delete / Select 기능 각각 구현
🔐 보안 PreparedStatement로 SQL Injection 방지
🔁 반복 처리 ResultSet을 활용한 다중 행 조회 처리
🧪 동적 실행기 사용자가 입력한 SQL을 실행하는 nativeQuery() 작성 (SQL Console 시뮬레이션)
💡 콘솔 인터페이스 메뉴 선택을 통한 반복 구조 설계 (while + switch)
 

 

🔷 키워드 요약:

  • JDBC 설정 및 연결
  • PreparedStatement와 Statement의 차이 이해
  • 기본적인 CRUD 구현
  • 콘솔 기반 SQL 입력 기능
  • ResultSetMetaData로 동적 결과 출력
  • 예외 처리 및 자원 해제 패턴

🧱 확장 가능성

영역 확장 예시
DAO 분리 JDBC 코드 → DAO 클래스로 분리
사용자 입력 하드코딩 값 → Scanner로 동적 입력
MVC 구조 DAO, DTO, Service 분리하여 관리
웹 개발 연결 이 구조를 Spring Boot 기반 REST API로 전환 가능
데이터 조작 도구 SQL 실습용 콘솔 툴로 재활용 가능 (교육 목적)
 


✅ DAO란?

**DAO(Data Access Object)**는

**데이터베이스와의 모든 상호작용을 담당하는 객체(또는 클래스)**입니다.

즉, INSERT, SELECT, UPDATE, DELETE 같은 SQL 쿼리 실행 코드를 한 곳에 모아서 관리하는 역할을 합니다.


🧱 왜 DAO가 필요할까?

1. 관심사 분리 (Separation of Concerns)

  • 비즈니스 로직데이터 접근 로직을 분리
  • 유지보수성과 재사용성을 높임

2. 중복 제거

  • 여러 클래스에서 DB에 접근하는 코드가 반복되면 → 한 곳에 모아 관리

3. 단위 테스트가 쉬움

  • DB 연동을 모킹(mock)하거나 테스트 더블로 대체 가능

💡 예시: DAO 없이 만든 구조

public class MainApp {
    public static void main(String[] args) throws SQLException {
        Connection con = DriverManager.getConnection(...);
        PreparedStatement ps = con.prepareStatement("SELECT * FROM phonebook");
        ResultSet rs = ps.executeQuery();
        ...
    }
}

→ DB 접근 코드가 로직에 섞여 혼란스럽고 확장성 낮음


✅ DAO 도입한 구조 예시

 
// PhonebookDao.java
public class PhonebookDao {
    private Connection con;

    public PhonebookDao(Connection con) {
        this.con = con;
    }

    public List<Phonebook> selectAll() throws SQLException {
        List<Phonebook> list = new ArrayList<>();
        String sql = "SELECT * FROM phonebook";
        PreparedStatement ps = con.prepareStatement(sql);
        ResultSet rs = ps.executeQuery();
        while (rs.next()) {
            Phonebook p = new Phonebook(
                rs.getInt("id"),
                rs.getString("name"),
                ...
            );
            list.add(p);
        }
        return list;
    }
}
// MainApp.java
public class MainApp {
    public static void main(String[] args) throws SQLException {
        Connection con = DriverManager.getConnection(...);
        PhonebookDao dao = new PhonebookDao(con);
        List<Phonebook> list = dao.selectAll();
        list.forEach(System.out::println);
    }
}

👉 DB 처리 로직은 PhonebookDao에만 집중
👉 MainApp은 화면 흐름 또는 입력 처리에만 집중


🧩 비유로 이해하는 DAO (Data Access Object)

비유 요소실세계 대응의미
📞 사용자 웹 애플리케이션, 서비스 로직 DB에 직접 접근하지 않음
💼 DAO (사무보조, 비서) 중간 관리자, DB와 대화하는 책임자 SQL 실행, 결과 가공
🏛 DB 전화번호부 보관소 데이터가 저장된 실제 장소
 

☎️ 사용자가 전화번호 하나를 찾고 싶다고 하면,
👉 직접 DB 창고에 들어가 검색하는 것이 아니라,
💼 DAO에게 "홍길동 전화번호 알려줘" 요청을 하면,
DAO가 DB에서 검색해서 값을 가져와 전달하는 중간 대행자 역할을 합니다.

 

 

✅ 정리

항목 내용
정의 DB 접근 로직을 담당하는 객체 (혹은 클래스)
역할 SQL 실행 (CRUD), 결과 반환
장점 구조 분리, 유지보수 쉬움, 테스트 용이
관련 개념 DTO, Service Layer, MVC 패턴 등과 함께 자주 사용됨

 

 

반응형