728x90
반응형
(구)웹에서 무지성으로 대충 내용만 알고 사용하던 방식을 이번에 정리가 하고 싶어서 작성하게 되었습니다.
PreparedStatement란?
PreparedStatement는 자바(Java)의 JDBC(Java Database Connectivity) API에서 제공하는 인터페이스로, 데이터베이스와 상호작용할 때 SQL 쿼리를 안전하고 효율적으로 실행할 수 있게 해주는 도구입니다.
기본 개념
PreparedStatement는 일반적인 Statement와 달리, SQL 쿼리를 미리 컴파일하고 실행 시점에 파라미터 값만 바인딩하는 방식으로 동작합니다.
작동 방식 (단계별)
- SQL 쿼리 준비: 물음표(?)를 사용하여 값이 들어갈 자리를 표시합니다.
- 쿼리 컴파일: 데이터베이스가 쿼리를 미리 분석하고 실행 계획을 준비합니다.
- 파라미터 바인딩: 실제 값들을 물음표(?) 위치에 설정합니다.
- 쿼리 실행: 준비된 쿼리를 실행합니다.
기본 사용법
// 1. 데이터베이스 연결 설정
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "username", "password");
// 2. PreparedStatement 생성 (물음표로 파라미터 위치 지정)
String sql = "SELECT * FROM users WHERE age > ? AND city = ?";
PreparedStatement pstmt = connection.prepareStatement(sql);
// 3. 파라미터 값 설정 (인덱스는 1부터 시작)
pstmt.setInt(1, 25);// 첫 번째 물음표에 25 설정
pstmt.setString(2, "서울");// 두 번째 물음표에 "서울" 설정// 4. 쿼리 실행 및 결과 처리
ResultSet resultSet = pstmt.executeQuery();
while (resultSet.next()) {
String name = resultSet.getString("name");
int age = resultSet.getInt("age");
System.out.println(name + ", " + age);
}
// 5. 자원 해제
resultSet.close();
pstmt.close();
connection.close();
PreparedStatement의 장점
1. SQL 인젝션 방지
SQL 인젝션은 악의적인 사용자가 입력 데이터를 통해 SQL 쿼리의 구조를 변경하는 공격입니다.
Statement(위험)의 경우:
String userInput = "' OR '1'='1";// 악의적인 입력
String sql = "SELECT * FROM users WHERE username = '" + userInput + "'";
// 결과 쿼리: SELECT * FROM users WHERE username = '' OR '1'='1'// 이 쿼리는 모든 사용자 정보를 반환합니다!
PreparedStatement(안전)의 경우:
String userInput = "' OR '1'='1";// 같은 악의적인 입력
String sql = "SELECT * FROM users WHERE username = ?";
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setString(1, userInput);
// 실제 실행: 문자열 "' OR '1'='1"을 찾는 안전한 쿼리
2. 성능 향상
- 쿼리 캐싱: 동일한 PreparedStatement를 여러 번 사용하면 데이터베이스가 실행 계획을 재사용합니다.
- 네트워크 트래픽 감소: 쿼리 자체는 한 번만 전송되고, 이후에는 파라미터만 전송됩니다.
3. 코드 가독성 향상
- 쿼리와 데이터가 분리되어 코드가 더 깔끔해집니다.
- 데이터 타입에 맞는 메서드(setString, setInt 등)를 사용하여 타입 안전성이 향상됩니다.
주요 메서드 설명
파라미터 설정 메서드
pstmt.setString(1, "홍길동");// 문자열 설정
pstmt.setInt(2, 30);// 정수 설정
pstmt.setDouble(3, 175.5);// 실수 설정
pstmt.setDate(4, java.sql.Date.valueOf("2023-01-01"));// 날짜 설정
pstmt.setNull(5, java.sql.Types.INTEGER);// NULL 값 설정
실행 메서드
// SELECT 쿼리 실행: 결과를 가져옴
ResultSet rs = pstmt.executeQuery();
// INSERT, UPDATE, DELETE 쿼리 실행: 영향받은 행의 수 반환
int rowsAffected = pstmt.executeUpdate();
// 모든 종류의 SQL 문 실행
boolean isResultSet = pstmt.execute();
실제 활용 예제
데이터 삽입 예제
// 사용자 정보 삽입 예제
String insertSQL = "INSERT INTO users (name, age, email) VALUES (?, ?, ?)";
PreparedStatement pstmt = connection.prepareStatement(insertSQL);
// 첫 번째 사용자 추가
pstmt.setString(1, "김철수");
pstmt.setInt(2, 28);
pstmt.setString(3, "kim@example.com");
pstmt.executeUpdate();
// 동일한 PreparedStatement로 두 번째 사용자 추가 (재사용)
pstmt.setString(1, "이영희");
pstmt.setInt(2, 25);
pstmt.setString(3, "lee@example.com");
pstmt.executeUpdate();
데이터 검색 및 처리 예제
// 나이 범위로 사용자 검색 예제
String selectSQL = "SELECT * FROM users WHERE age BETWEEN ? AND ?";
PreparedStatement pstmt = connection.prepareStatement(selectSQL);
pstmt.setInt(1, 20);// 최소 나이
pstmt.setInt(2, 30);// 최대 나이
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
int age = rs.getInt("age");
String email = rs.getString("email");
System.out.println("ID: " + id + ", 이름: " + name + ", 나이: " + age + ", 이메일: " + email);
}
자주 하는 실수와 주의사항
- 인덱스 번호 오류: 파라미터 인덱스는 1부터 시작합니다(0부터가 아님).
- // 올바른 사용 pstmt.setString(1, "값");// 첫 번째 파라미터// 잘못된 사용 pstmt.setString(0, "값");// 오류 발생!
- 자원 누수 방지: try-with-resources 구문 사용을 권장합니다.
- try ( Connection conn = DriverManager.getConnection(url, user, password); PreparedStatement pstmt = conn.prepareStatement(sql); ResultSet rs = pstmt.executeQuery() ) { // 코드 작성 } catch (SQLException e) { e.printStackTrace(); } // 자동으로 자원이 닫힘
- 타입 불일치: 데이터 타입에 맞는 set 메서드를 사용해야 합니다.
- // 잘못된 사용 pstmt.setString(1, 123);// 컴파일 오류// 올바른 사용 pstmt.setInt(1, 123); // 또는 pstmt.setString(1, "123");// 문자열로 처리하고 싶은 경우
요약
PreparedStatement는:
- SQL 쿼리에 파라미터를 안전하게 삽입하는 방법을 제공합니다.
- SQL 인젝션 공격을 방지합니다.
- 실행 계획 캐싱을 통해 성능을 향상시킵니다.
- 코드 가독성과 유지보수성을 높여줍니다.
데이터베이스 작업에서 일반 Statement 대신 PreparedStatement를 사용하는 것이 거의 항상 좋은 선택입니다. 특히 사용자 입력이 포함된 쿼리나 동일한 쿼리를 반복 실행하는 경우에 더욱 그렇습니다.
반응형
'Java > Java' 카테고리의 다른 글
Java 음성 소켓 통신(서버, 클라이언트) 기초 (0) | 2023.04.21 |
---|---|
JAVA 채팅 프로그램 (0) | 2022.10.20 |
JAVA (TCP/IP, 서버 클라이언트) (0) | 2022.10.20 |
JAVA 네트워크 (0) | 2022.10.20 |
자바 제네릭(Generic) (0) | 2022.10.12 |