[Java] 자바 이클립스 JDBC 5. Statement와 PreparedStatement 비교
Statement와 PreparedStatement의 차이
1) 보안
Statement:
- 사용자가 입력한 값을 가지고 SQL문을 만들기 때문에 보안이 취약하다.
- 즉 악의적으로 SQL의 일부를 포함하는 값을 입력할 수 있다.
PreparedStatement
- ?(in-parameter) 자리에 임의의 SQL문을 삽입할 수 없다.
- 삽입해봐야 단순 문자열로 취급한다.
- 그래서 보안 문제를 발생시키지 않는다.
2) 바이너리 데이터
Statement
- 문자열로 SQL문을 만들기 때문에 바이너리 데이터를 삽입할 수 없다.
PreparedStatement
- ?(in-parameter) 자리에 바이너리 데이터를 삽입할 수 있다.
3) 코드의 가독성
Statement
- + 연산자를 사용하여 컬럼의 값을 연결하는 식으로 문자열을 만들기 때문에,
컬럼의 개수가 많으면 문자열을 붙이는 코드도 산만해지고 복잡해진다.
PreparedStatement
- setXxx()를 사용하여 값을 넣기 때문에 코드가 간결하다.
4) 실행속도
서버에 SQL문을 전달하기 전에 서버에서 원하는 형식으로 변환하여 보낸다.
단순히 SQL을 한 번만 실행한다면 Statement나 PreparedStatement 둘 다 속도가 같다.
그러나 같은 SQL문을 값을 바꿔가면서 여러 번 실행할 경우,
PreparedStatement는 SQL문을 컴파일한 후 값만 넣어서 보내기 때문에 속도가 빠르다.
Statement는 executeXxx()를 실행할 때마다 SQL문을 매번 컴파일하기 때문에 속도가 느리다.
JDBC 프로그래밍: PreparedStatement 객체 사용 후
- 더하기 연산자를 사용하여 SQL문을 만드는 대신,
in-parameter '?' 를 사용하여 SQL 문을 만든다.
JDBC SQL에서 PreparedStatement의 사용 예제
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
public class Test05_2 {
public static void main(String[] args) throws Exception {
// 원래는 값을 JVM 아규먼트나 프로그램 아규먼트 등 외부로부터 받아야 하지만,
// 테스트를 원활하게 하기 위해서 변수에 값을 담아 놓자!
String jdbcDriver = "com.mysql.jdbc.Driver";
String jdbcUrl = "jdbc:mysql://localhost:3306/데이터베이스명";
String jdbcUsername = "유저명";
String jdbcPassword = "1111";
String name = "홍길동102";
String email = "hong102@test.com";
String tel = "1111-1111";
String password = "1111";
try {
Class.forName(jdbcDriver);
} catch (Exception e) {
e.printStackTrace();
}
try (
Connection con = DriverManager.getConnection(jdbcUrl, jdbcUsername,jdbcPassword);
// SQL 문을 미리 작성해둔다. 값(문자, 숫자 상관없이)이 들어갈 자리는 ?을 사용하여 비워둔다.
// 이때 ?를 in-parameter라 부른다.
// preparedStatement()의 리턴 값은 java.sql.PreparedStatement의 구현체이다.
PreparedStatement stmt = con.prepareStatement("insert into memb(name, tel, email, pwd) values(?,?,?,password(?))");
) {
// SQL문을 서버에 보내기 전에 in-parameter 자리에 값을 채운다.
// 컬럼의 타입에 따라 호출하는 메서드가 다르다.
// => setXxx(컬럼인덱스, 값)
// => 컬럼 인덱스는 1부터 시작한다.
// 빈자리(in-parameter)에 값을 넣을 때 컬럼의 순서를 지킬 필요는 없다.
// 그렇다고 굳이 임의 순서대로 넣는 것은 코드의 이해도를 떨어뜨린다.
stmt.setString(1, name);
stmt.setString(2, tel);
stmt.setString(3, email);
stmt. setString(4, password);
// 이렇게 setXxx()를 호출하여 SQL 문을 완성하면,
// + 연산자를 사용하여 SQL문을 완성하는 방법보다 편리하고 가독성이 좋다.
// 위에서 SQL문을 준비하고 값을 채웠기 때문에 여기에서는 그냥 실행만 하면 된다.
int count = stmt.executeUpdate("insert into memb(name, tel, email, pwd) values('" +
name + "', '"+
tel + "', '"+
email + "', password('" +
password + "'))");
System.out.println(count);
} catch (Exception e) {
e.printStackTrace();
}
}
}