- JDBC(Java Database Connectivity)의 기본 개념 이해
- Oracle 데이터베이스 연결 방법 학습
- Statement와 PreparedStatement의 차이점 파악
- 기본 CRUD(Create, Read, Update, Delete) 작업 구현
리 컴파일된 SQL문을 실행하는 객체 (성능 향상, SQL Injection 방지)
- ResultSet: SELECT문 실행 후 조회된 결과를 담는 객체
환경 설정
1. JDBC 드라이버 다운로드 및 설정
드라이버 다운로드
- 다운로드 링크: https://www.oracle.com/asean/database/technologies/appdev/jdbc-downloads.html
- JDK 17 기준: ojdbc17.jar 다운로드
- 저장 위치: C://devtool에 저장
자바 프로젝트에 추가
- 프로젝트 우클릭 → Build Path → Add External Archives...
- 다운로드한 ojdbc17.jar 선택 → 추가
- Referenced Libraries에 ojdbc17.jar가 보이면 성공
2. 프로젝트 설정
- 자동 생성된 Module 삭제 (JDBC 사용을 위해 필요)
3. 데이터베이스 연결 정보
- URL: jdbc:oracle:thin:@localhost:1521:xe
- 계정: C##JDBC
- 비밀번호: JDBC
참고: 127.0.0.1 또는 localhost는 현재 실행중인 컴퓨터의 IP를 의미한다.
SQL - TABLE 미리 생성
- 계정 새로 생성
-- 사용자 계정 생성
CREATE USER C##JDBC IDENTIFIED BY JDBC;
-- 접속 권한 및 테이블 생성 권한 부여
GRANT CONNECT, RESOURCE TO C##JDBC;
-- 테이블스페이스 설정
ALTER USER C##JDBC DEFAULT TABLESPACE USERS QUOTA UNLIMITED ON USERS;
TEST 테이블 작성.
CREATE TABLE TEST(
TNO NUMBER PRIMARY KEY,
TNAME VARCHAR2(100) NOT NULL,
TDATE DATE DEFAULT SYSDATE NOT NULL
);

이후 Eclipse 다시 사용
<INSERT> (Statement 사용)
public static void insertWithStatement() {
Connection conn = null;
Statement stmt = null;
Scanner sc = new Scanner(System.in);
int result = 0;
// 사용자 입력 받기
System.out.print("번호 : ");
int tno = sc.nextInt();
System.out.print("이름 : ");
String tName = sc.next();
// SQL문 작성 (주의: SQL Injection 위험)
String sql = "INSERT INTO TEST VALUES(" + tno + ", '" + tName + "', SYSDATE)";
try {
// 1) JDBC 드라이버 등록
Class.forName("oracle.jdbc.driver.OracleDriver");
// 2) Connection 생성
conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "C##JDBC", "JDBC");
conn.setAutoCommit(false); // 자동커밋 해제
// 3) Statement 생성
stmt = conn.createStatement();
// 4) SQL문 실행
result = stmt.executeUpdate(sql);
// 5) 트랜잭션 처리
if(result > 0) {
conn.commit(); // 성공시 커밋
} else {
conn.rollback(); // 실패시 롤백
}
} catch (SQLException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
// 6) 자원 반납 (생성의 역순)
try {
if(stmt != null) stmt.close();
if(conn != null) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
실행 결과:
번호 : 1
이름 : 홍길동
OracleDriver 등록성공
데이터 추가 성공

<SELECT> (ResultSet 활용)

public static void selectData() {
Connection conn = null;
Statement stmt = null;
ResultSet rset = null;
List<Test> list = new ArrayList<>();
String sql = "SELECT * FROM TEST";
try {
// 1) 드라이버 등록
Class.forName("oracle.jdbc.driver.OracleDriver");
// 2) Connection 생성
conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "C##JDBC", "JDBC");
// 3) Statement 생성
stmt = conn.createStatement();
// 4) SQL 실행 (SELECT는 executeQuery 사용)
rset = stmt.executeQuery(sql);
// 5) ResultSet에서 데이터 추출
while(rset.next()) { // 다음 행이 있는지 확인하고 이동
int tno = rset.getInt("TNO");
String tName = rset.getString("TNAME");
Date tDate = rset.getDate("TDATE");
list.add(new Test(tno, tName, tDate.toLocalDate()));
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
// 자원 반납 (생성의 역순)
try {
if(rset != null) rset.close();
if(stmt != null) stmt.close();
if(conn != null) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
// 결과 출력
if(list.isEmpty()) {
System.out.println("데이터가 없습니다.");
} else {
System.out.println(list);
}
}
결과

<UPDATE> (PreparedStatement 사용)
public static void updateWithPreparedStatement() {
Scanner sc = new Scanner(System.in);
Connection conn = null;
PreparedStatement pstmt = null;
int result = 0;
// 사용자 입력
System.out.print("수정할 TNO를 입력 : ");
int tno = sc.nextInt();
System.out.print("새로운 이름을 입력 : ");
String newName = sc.next();
System.out.print("새로운 날짜를 입력(YYYY-MM-DD) : ");
String newDate = sc.next();
// PreparedStatement용 SQL문 (? 플레이스홀더 사용)
String sql = "UPDATE TEST SET TNAME=?, TDATE=TO_DATE(?,'YYYY-MM-DD') WHERE TNO=?";
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "C##JDBC", "JDBC");
conn.setAutoCommit(false);
// 미완성된 SQL문으로 PreparedStatement 생성
pstmt = conn.prepareStatement(sql);
// ? 플레이스홀더에 값 설정 (1부터 시작)
pstmt.setString(1, newName); // 첫 번째 ?
pstmt.setString(2, newDate); // 두 번째 ?
pstmt.setInt(3, tno); // 세 번째 ?
// SQL 실행
result = pstmt.executeUpdate();
// 트랜잭션 처리
if(result > 0) {
conn.commit();
} else {
conn.rollback();
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
try {
if(pstmt != null) pstmt.close();
if(conn != null) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
sc.close();
if(result > 0) {
System.out.println(result + "개의 행 UPDATE");
} else {
System.out.println("UPDATE 실패");
}
}
실행 결과:


Statement vs PreparedStatement 비교
구분 Statement PreparedStatement
| SQL 작성 | 완성된 SQL문 전달 | ? 플레이스홀더 사용 |
| 성능 | 매번 컴파일 | 미리 컴파일되어 재사용 |
| 보안 | SQL Injection 위험 | SQL Injection 방지 |
| 사용법 | stmt.executeUpdate(sql) | pstmt.setString(1, value) |
| 권장도 | ❌ 귀찮고 번거로움 | ✅ ? 개수만 잘 맞추면 편해짐 |
JDBC 작업 단계 (공통 패턴)
전체 프로세스 흐름도
1. 드라이버 등록 → 2. Connection 생성 → 3. Statement 생성
→ 4. SQL 실행 → 5. 트랜잭션 처리 → 6. 자원 반납
상세 단계별 설명
1단계: 드라이버 등록
Class.forName("oracle.jdbc.driver.OracleDriver");
- 목적: JDBC 드라이버 클래스를 JVM에 로드
- 참고: 최신 JDBC에서는 생략 가능하지만 명시적으로 작성하는 것을 권장
2단계: Connection 생성
conn = DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:xe", "C##JDBC", "JDBC");
conn.setAutoCommit(false); // 수동 트랜잭션 설정
- 목적: 데이터베이스와의 연결 통로 생성
- AutoCommit 해제: 트랜잭션을 수동으로 관리하기 위함
3단계: Statement/PreparedStatement 생성
// Statement 방식
Statement stmt = conn.createStatement();
// PreparedStatement 방식 (권장)
PreparedStatement pstmt = conn.prepareStatement(sql);
4단계: SQL 실행
- INSERT/UPDATE/DELETE: executeUpdate() → int 반환 (영향받은 행 수)
- SELECT: executeQuery() → ResultSet 반환 (조회 결과)
5단계: 트랜잭션 처리
if(result > 0) {
conn.commit(); // 성공시 커밋
} else {
conn.rollback(); // 실패시 롤백
}
6단계: 자원 반납
// 생성의 역순으로 반납
if(rset != null) rset.close(); // ResultSet (있는 경우)
if(stmt != null) stmt.close(); // Statement
if(conn != null) conn.close(); // Connection
- 중요: null 체크 후 close() 호출
- 순서: 생성의 역순으로 반납해야 함
주의사항
1. 자원 관리
- 반드시 finally 블록에서 자원 반납
- null 체크 후 close() 호출
- 생성의 역순으로 반납: ResultSet → Statement → Connection
finally {
try {
if(rset != null) rset.close();
if(stmt != null) stmt.close();
if(conn != null) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
2. 트랜잭션 처리
- setAutoCommit(false) 설정으로 수동 트랜잭션 관리
- 성공 시 commit(), 실패 시 rollback() 호출
- 원자성(Atomicity) 보장: 모든 작업이 성공하거나 모두 실패
3. SQL Developer와의 연동 이슈
- 중요: SQL Developer에서 INSERT한 데이터는 COMMIT 완료 후 Eclipse에서 확인 가능
INSERT INTO TEST VALUES(4, '홍길동', SYSDATE);




>>> 트랜잭션이 완료되지 않으면 다른 세션에서 데이터를 볼 수 없다!
4. PreparedStatement 사용 권장 이유
SQL Injection 방지
// 위험한 Statement 방식
String sql = "SELECT * FROM USER WHERE ID='" + userId + "'";
// 만약 userId에 "admin'; DROP TABLE USER; --"가 입력되면?
// 안전한 PreparedStatement 방식
String sql = "SELECT * FROM USER WHERE ID=?";
pstmt.setString(1, userId); // 자동으로 이스케이프 처리
성능 향상
- SQL문을 미리 컴파일해두고 값만 변경하여 재사용
- 같은 구조의 SQL을 반복 실행할 때 성능상 이점
5. 예외 처리 패턴
try {
// JDBC 작업 수행
} catch (ClassNotFoundException e) {
// 드라이버 클래스를 찾을 수 없을 때
System.out.println("JDBC 드라이버를 확인하세요.");
} catch (SQLException e) {
// SQL 실행 중 오류 발생
System.out.println("데이터베이스 연결 또는 SQL 실행 오류");
e.printStackTrace();
} finally {
// 자원 반납
}
- PreparedStatement 사용 권장 - 성능과 보안 향상
- 자원 관리의 중요성 - 메모리 누수 방지
- 트랜잭션 처리 - 데이터 일관성 보장
- 예외 처리 - 안정적인 프로그램 작성
'JDBC' 카테고리의 다른 글
| [JAVA_JDBC] 프로그램 제작 (2) | 2025.09.05 |
|---|---|
| JDBC_02) MVC 패턴 (5) | 2025.08.27 |