Statement
- 자바에서 쿼리문을 사용할때 java.sql 패키지에 있는 Statement를 사용한다.
(statement : 성명, 기재, 이야기 라는 뜻을 가짐 sql문을 담아서 실행시키는 객체라고 생각하면 될듯)
- 명령문장이라고 생각해도 된다. DB에 쿼리의 수행을 지시하는 명령이다.
Statement의 동작 방식
(쿼리 문장 분석 > 컴파일 > 실행 > 출력)
[사용해보기]
String sqlstr = "SELECT name, memo FROM TABLE WHERE name =" + num
Statement stmt = conn.createStatement();
ResultSet rst = stmt.executeQuery(sqlstr);
실행되는 쿼리문을 한눈에 확인하기 좋지만 쿼리문의 수정을 하거나 작성을 할때 하나하나 입력해 주어야 한다는 단점
PreparedStatement
- PreparedStatement는 Statement를 상속하고 있는 인터페이스이다.
- PreparedStatement는 내부적으로 Statement의 4단계 과정중 parse과정의 결과를 캐쉬 처리하고 나머지만 처리하여 Sql 구문을 실행한다.
- PreparedStatement가 SQL Injection을 방어 할 수 있다고 한다.
- Statement와 동일한 기능을 제공한다. 차이점이 있다면 PreparedStatement는 SQL 쿼리의 틀을 미리 생성해 놓고 나중에 값을 지정한다.
[사용 순서]
- Connection.prepareStatement() 메소드를 사용하여 PreparedStatement 생성
- PreparedStatement의 set 메소드를 사용해서 필요한 값 지정 (ex - setString, setInt ... )
- PreparedStatement의 excuteQuery() 또는 excuteUpdate() 메소드를 사용하여 쿼리 실행
- finally 블록에서 사용한 객체 닫기 close()
[사용해보기]
String sqlstr = "SELECT name, memo FROM TABLE WHERE num = ?"
PreparedStatement stmt = conn.preparedStatement();
stmt.setInt(1, num);
ResultSet rst = stmt.executeQuery(sqlstr);
미리 컴파일이 되었기 때문에 Statement에 비해 성능이 좋다.
특수문자를 자동으로 파싱해주기 때문에 SQL injection같은 공격을 막을 수 있다.
"?" 부분에만 변화를 주어 쿼리문을 수행하므로 실행되는 SQL문을 파악하기 어렵다.
(예)
select * from user where id=? and password = ?;
위와 같은 형식으로 쿼리를 작성하고 ? 부분에 값을 삽입하는 형식으로 진행
PreparedStatement pstmt
connection conn 에 대하여
pstmt = conn.prepareStatemt("select* from user where id=? and password=? ");
<!--구문 분석을 캐싱하는 과정에서 ? 자리를 채워 넣을 값들을 넣어준다.
pstmt.setString(1,"banana");
다음과 같이 작성하면 1번째 물음표 자리에 banana를 삽입하겠다는 의미
pstmt.setInt(2,7777);
2번째 물음표 자리에 정수 7777을 대입하겠다는 의미
즉 현재 쿼리는 select* from user where id="banana" and password=7777 이다.-->
<!--구문 작성이 끝나면 이제 결과를 도출해 준다-->
ResultSet rs = pstmt.excuteQuery();
Prepared Statement를 사용해야 하는경우
- 사용자가 입력값으로 쿼리문을 실행하는경우 - 특수기호가 들어오더라도 알아서 파싱해주므로 이로인한 에러를 막을 수 있다.
- 쿼리 반복 수행작업일 경우
(예) 이름으로 db에서 필요한 자료를 검색하는 프로그램 구현하기
프론트 작성 (studentName.html)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Select Student Table 이름 조회 결과</title>
</head>
<body>
<%@ page import="java.sql.*"%>
<%
request.setCharacterEncoding("UTF-8");
%>
<h2>Table Student 에서 이름으로 조회하는 프로그램</h2>
<hr size="5" color="red">
<h2>학생 정보 조회</h2>
<%
Connection conn = null;
PreparedStatement pstmt = null;
String driverName = "oracle.jdbc.driver.OracleDriver";
String dbURL = "jdbc:oracle:thin:@localhost:1521:orcl";
int rowCount = 0;
try {
Class.forName(driverName);
conn = DriverManager.getConnection(dbURL, "scott", "tiger");
if (request.getParameter("search").equals("name")) {
String name = request.getParameter("search22") + "%";
String sql = "select * from student where name like ?";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, name);
} else if (request.getParameter("search").equals("year")) {
int year = Integer.parseInt(request.getParameter("search22"));
String sql = "select * from student where year =?";
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, year);
} else if (request.getParameter("search").equals("depart")) {
String depart = request.getParameter("search22") + "%";
String sql = "select * from student where depart like ?";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, depart);
}
ResultSet result = pstmt.executeQuery();
%>
<table border="2">
<tr>
<td align="center"><b>아이디</b></td>
<td align="center"><b>암호</b></td>
<td align="center"><b>이름</b></td>
<td align="center"><b>입학년도</b></td>
<td align="center"><b>학번</b></td>
<td align="center"><b>학과</b></td>
<td align="center"><b>휴대폰1</b></td>
<td align="center"><b>휴대폰2</b></td>
<td align="center"><b>주소</b></td>
<td align="center"><b>이메일</b></td>
</tr>
<%
while (result.next()) {
%>
<tr>
<td align="center"><%=result.getString(1)%></td>
<td align="center"><%=result.getString(2)%></td>
<td align="center"><%=result.getString(3)%></td>
<td align="center"><%=result.getString(4)%></td>
<td align="center"><%=result.getString(5)%></td>
<td align="center"><%=result.getString(6)%></td>
<td align="center"><%=result.getString(7)%></td>
<td align="center"><%=result.getString(8)%></td>
<td align="center"><%=result.getString(9)%></td>
<td align="center"><%=result.getString(10)%></td>
</tr>
<%
rowCount++;
}
result.close();
} catch (SQLException e) {
out.println("Oracle Database Student 테이블 조회에 문제가 있습니다.");
out.println(e.getMessage());
e.printStackTrace();
} finally {
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close();
}
%>
</table>
<hr size="5" color="green">
</body>
</html>
selectName.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Select Student Table 이름 조회 결과</title>
</head>
<body>
<%@ page import="java.sql.*"%>
<%
request.setCharacterEncoding("UTF-8");
%>
<h2>Table Student 에서 이름으로 조회하는 프로그램</h2>
<hr size="5" color="red">
<h2>학생 정보 조회</h2>
<%
Connection conn = null;
PreparedStatement pstmt = null;
String driverName = "oracle.jdbc.driver.OracleDriver";
String dbURL = "jdbc:oracle:thin:@localhost:1521:orcl";
int rowCount = 0;
try {
Class.forName(driverName);
conn = DriverManager.getConnection(dbURL, "scott", "tiger");
if (request.getParameter("search").equals("name")) {
String name = request.getParameter("search22") + "%";
String sql = "select * from student where name like ?";
//? 자리에 setString을이용해서 다른 String을 덧붙인다. 이때 덧붙일 것의 개수만큼 ?를 작성(덧붙이고 싶은 위치에 작성)
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, name); // pstmt에 1번째 물음표 위치에 문자를 덧붙인다. 이때 덧붙이는 것은 name
// 만약 물음표기 A?BC? D? 라고 적혀있고 A뒤에 붙이고 싶으면 1 BC뒤에 붙이고 싶으면 2 이런식으로 덧붙이고자 하는 물음표 순서번호를 작성해준다.
} else if (request.getParameter("search").equals("year")) {
int year = Integer.parseInt(request.getParameter("search22"));
String sql = "select * from student where year =?";
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, year);
} else if (request.getParameter("search").equals("depart")) {
String depart = request.getParameter("search22") + "%";
String sql = "select * from student where depart like ?";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, depart);
}
ResultSet result = pstmt.executeQuery();
%>
<table border="2">
<tr>
<td align="center"><b>아이디</b></td>
<td align="center"><b>암호</b></td>
<td align="center"><b>이름</b></td>
<td align="center"><b>입학년도</b></td>
<td align="center"><b>학번</b></td>
<td align="center"><b>학과</b></td>
<td align="center"><b>휴대폰1</b></td>
<td align="center"><b>휴대폰2</b></td>
<td align="center"><b>주소</b></td>
<td align="center"><b>이메일</b></td>
</tr>
<%
while (result.next()) {
%>
<tr>
<td align="center"><%=result.getString(1)%></td>
<td align="center"><%=result.getString(2)%></td>
<td align="center"><%=result.getString(3)%></td>
<td align="center"><%=result.getString(4)%></td>
<td align="center"><%=result.getString(5)%></td>
<td align="center"><%=result.getString(6)%></td>
<td align="center"><%=result.getString(7)%></td>
<td align="center"><%=result.getString(8)%></td>
<td align="center"><%=result.getString(9)%></td>
<td align="center"><%=result.getString(10)%></td>
</tr>
<%
rowCount++;
}
result.close();
} catch (SQLException e) {
out.println("Oracle Database Student 테이블 조회에 문제가 있습니다.");
out.println(e.getMessage());
e.printStackTrace();
} finally {
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close();
}
%>
</table>
<hr size="5" color="green">
</body>
</html>
이때 라디오 버튼을 선택하고 search22 에 아무 값도 입력하지 않고 검색을 하게되면 student table 전체가 검색이 된다.
search22 에 아무 값도 입력하지 않으면 null 이 넘어가게 된다.
만약 name 을 클릭하고 넘어갔다고 하면 sql 문은 select* from student where name like null% 이 되는걸까?
를생각해보면 이는 문법상 옳지 않다. 이것은 sql 자체로는 불가능하다.
하지만 위의 코드 내부에서는 모든 name을 선택한 것으로 처리 되어 모든 결과 값이 나온다.