
자바가 데이터베이스에 말을 거는 순서입니다.
6편에서 파일에 데이터를 저장했습니다. 껐다 켜도 남으니 큰 진전이었죠. 그런데 회원이 만 명쯤 되면 어떨까요. 파일에서 특정 사람을 찾으려면 처음부터 끝까지 읽어야 하고, 이름순 정렬도 직접 짜야 하고, 여러 사람이 동시에 고치면 뒤엉킵니다.
이런 일을 대신해 주는 전문가가 데이터베이스(DB)입니다. 그리고 자바가 그 DB에 말을 걸 때 쓰는 표준 방법이 오늘의 주제, JDBC입니다.
JDBC가 뭔가요?
JDBC(Java Database Connectivity)는 자바와 데이터베이스 사이의 표준 통역기입니다.
세상에는 MySQL, 오라클, PostgreSQL처럼 DB 제품이 여럿 있고 저마다 말투가 조금씩 다릅니다. JDBC는 그 사이에 서서 "자바 쪽에서는 이렇게만 부르면 된다"는 공통 규칙을 제공합니다. 덕분에 DB를 바꿔도 자바 코드는 크게 손대지 않습니다.
쉽게 — 해외 거래처와 일하는 상황과 같습니다. 상대가 어느 나라 사람이든 나는 통역사에게 한국어로 말하면 되죠. 통역사(드라이버)만 그 나라 사람으로 바꿔 끼우면 됩니다. JDBC가 정해 둔 것은 "통역사에게 말 거는 방식"입니다.
세 명의 담당자
JDBC를 쓸 때 계속 등장하는 객체가 셋입니다. 역할을 사람에 빗대면 헷갈리지 않습니다.
- Connection — DB와 연결된 전화선입니다. 이게 있어야 대화가 시작됩니다.
- PreparedStatement — 보낼 질문지입니다. SQL을 담아 DB에 전달합니다.
- ResultSet — 돌아온 결과표입니다. 조회했을 때만 생깁니다.
이 셋이 순서대로 만들어지고, 나중에 거꾸로 닫힙니다. 이 대칭이 JDBC 코드의 기본 골격입니다.
연결하고 물어보기
실제 코드입니다. 먼저 연결까지.
String url = "jdbc:mysql://localhost:3306/mydb"; // 어느 DB인지
String id = "root";
String pw = "1234";
Class.forName("com.mysql.cj.jdbc.Driver"); // 1) 통역기 불러오기
Connection conn = DriverManager.getConnection(url, id, pw); // 2) 연결
System.out.println("연결됐습니다");
url은 DB의 주소입니다. 8편에서 본 것처럼 localhost는 내 컴퓨터, 3306은 MySQL이 쓰는 포트 번호이고, 맨 뒤는 데이터베이스 이름입니다. 소켓 때 배운 주소·포트 개념이 여기서도 그대로 쓰입니다.
연결이 됐으면 질문을 던집니다.
PreparedStatement pstmt = conn.prepareStatement("select no, name from member");
ResultSet rs = pstmt.executeQuery(); // 조회는 executeQuery
while (rs.next()) { // 한 줄씩 내려가며
System.out.println(rs.getInt("no") + ". " + rs.getString("name"));
}
rs.next()가 핵심입니다. 결과표의 커서를 한 줄 아래로 내리고, 읽을 줄이 있으면 true를 돌려줍니다. 그래서 while과 짝을 이룹니다. 값을 꺼낼 때는 타입에 맞춰 getInt, getString처럼 부릅니다.
넣고 고치고 지우는 작업은 메서드가 다릅니다. 조회는 executeQuery, 그 외(INSERT·UPDATE·DELETE)는 executeUpdate를 쓰고 바뀐 줄 수를 돌려받습니다.
물음표 하나가 막아 줍니다
여기서 반드시 짚어야 할 것이 있습니다. 사용자가 입력한 값을 SQL에 넣을 때의 이야기입니다.

그림 1. 입력값은 문장이 아니라 값으로만 취급돼야 합니다.
이렇게 쓰고 싶은 유혹이 생깁니다.
// 절대 이렇게 쓰지 마세요
String sql = "select * from member where name = '" + input + "'";
문자열을 이어 붙였으니 편해 보입니다. 그런데 사용자가 이름 칸에 ' or '1'='1 같은 것을 넣으면, 완성된 SQL은 조건이 항상 참이 되어 회원 전체가 조회됩니다. 입력값이 값이 아니라 문장의 일부로 섞여 들어갔기 때문입니다. 이것이 SQL 인젝션입니다.
PreparedStatement가 이걸 막아 줍니다.
PreparedStatement pstmt = conn.prepareStatement(
"select * from member where name = ?"); // 자리를 비워 두고
pstmt.setString(1, input); // 값만 따로 채움
ResultSet rs = pstmt.executeQuery();
물음표로 자리를 비워 두면 DB는 문장 구조를 먼저 확정한 뒤 값을 끼웁니다. 그래서 입력에 따옴표가 들어 있어도 그냥 이름의 일부로 취급될 뿐, 문장을 바꾸지 못합니다. 숫자는 setInt, 문자열은 setString을 쓰고, 번호는 물음표 순서대로 1부터 셉니다.
PreparedStatement를 쓰는 이유가 편의가 아니라 안전 때문이라는 점을 기억해 두면 좋습니다.
닫는 순서가 있습니다
다 쓴 자원은 닫아야 합니다. 6편의 파일, 8편의 소켓과 같은 원칙입니다. 다만 JDBC는 닫는 순서가 만든 순서의 반대입니다.
finally {
try { rs.close(); } catch (Exception e) { } // 결과표
try { pstmt.close(); } catch (Exception e) { } // 질문지
try { conn.close(); } catch (Exception e) { } // 전화선
}
늦게 만든 것부터 닫습니다. 전화선을 먼저 끊어 버리면 그 위에 얹힌 결과표를 정리할 수 없기 때문입니다. finally에 넣는 이유도 분명합니다. 1편에서 배운 대로 예외가 나든 안 나든 반드시 실행되어야 하니까요.
연결을 안 닫으면 DB 쪽에 연결이 계속 쌓입니다. 개수 제한에 걸리면 어느 순간부터 새 연결이 거부되는데, 원인을 찾기 까다로운 사고 유형입니다.
이 위험을 직접 보기
실제 DB 연결은 서버가 필요해 브라우저에서 돌릴 수 없습니다. 대신 문자열을 이어 붙이면 SQL이 어떻게 망가지는지는 눈으로 확인할 수 있습니다. 아래를 돌려 보세요.
public class Main {
public static void main(String[] args) {
String normal = "홍길동";
String attack = "' or '1'='1"; // 공격자가 넣은 입력
// 이어 붙이는 방식
String sql1 = "select * from member where name = '" + normal + "'";
String sql2 = "select * from member where name = '" + attack + "'";
System.out.println("정상 입력:");
System.out.println(" " + sql1);
System.out.println();
System.out.println("공격 입력:");
System.out.println(" " + sql2);
System.out.println();
System.out.println("→ 조건이 항상 참이 되어 전체가 조회됩니다.");
System.out.println("→ 물음표(?)를 쓰면 입력은 이름 값으로만 취급됩니다.");
}
}📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.
출력된 두 번째 SQL을 소리 내어 읽어 보면 조건이 왜 무너지는지 바로 보입니다.
한 장 정리
| 항목 | 내용 |
|---|---|
| JDBC | 자바와 DB 사이의 표준 통역 규칙 |
| Connection | DB와 이어진 연결 (전화선) |
| PreparedStatement | SQL을 담아 보내는 질문지 |
| ResultSet | 조회 결과표, next()로 한 줄씩 |
| 조회 vs 변경 | executeQuery / executeUpdate |
| 안전 | 값은 물음표 자리표시자로 — 이어 붙이기 금지 |
| 닫기 | 만든 반대 순서로, finally에서 |
이것만 기억하면 됩니다. JDBC는 연결하고, 질문지를 보내고, 결과표를 읽는 세 박자입니다. 자원은 만든 반대 순서로 닫고, 사용자 입력은 절대 문자열로 이어 붙이지 말고 물음표에 값으로 채워 넣으세요.
미니 퀴즈
개념을 제대로 잡았는지 직접 풀어 봅니다. 정답은 눌러야 나옵니다.
미니 퀴즈
포켓코딩(JAVA3) 10편 · 예제 출처: 강사 개인 GitHub 저장소. 다음 편: 트랜잭션 — 여러 작업을 하나로 묶기.