Statement를 사용한 쿼리실행
Connection 객체를 생성한 후에 Connection 으로부터 Statement 를 생성하여 쿼리를 실행합니다.
다음과 같이 Connection.createStatement() 메서드를 사용하여 생성해줍니다.
▶ Statement stmt = conn.createStatement();
Statement 클래스를 생성한 후엔 다음의 두 메서드를 이용하여 쿼리를 실행해줍니다.
▶ ResultSet executeQuery(String query) : SELECT 쿼리 실행 / 결과값을 ResultSet 객체에 저장해서 리턴.
▶ int executeUpdate(String query) : INSERT, UPDATE, DELETE 쿼리 실행 / 변경 또는 삽입된 레코드의 개수를 리턴.
아래와 같이 예제를 구성하고 실습해보겠습니다.
<updateForm.jsp>
- <%@ page language="java" contentType="text/html; charset=EUC-KR" pageEncoding="EUC-KR"%>
- <html>
- <head>
- <title>NameUpdateForm</title>
- </head>
- <body>
- <form action="<%=request.getContextPath() %>/update/update.jsp" method="post">
- <table border="1" cellpadding="0" cellspacing="0">
- <tr>
- <td>아이디</td>
- <td><input type="text" name="memberID" size="10"/></td>
- <td>새로운아이디</td>
- <td><input type="text" name="name" size="10"/></td>
- </tr>
- <tr>
- <td colspan="4">
- <input type="submit" value="변경"/>
- </td>
- </tr>
- </table>
- </form>
- </body>
- </html>
<update.jsp>
- <%@ page language="java" contentType="text/html; charset=EUC-KR" pageEncoding="EUC-KR"%>
- <%@ page import="java.sql.DriverManager"%>
- <%@ page import="java.sql.Connection"%>
- <%@ page import="java.sql.Statement"%>
- <%@ page import="java.sql.SQLException"%>
- <%
- request.setCharacterEncoding("euc-kr");
- String memberID = request.getParameter("memberID");
- String name = request.getParameter("name");
- int updateCount = 0;
- Class.forName("com.mysql.jdbc.Driver");
- Connection conn = null;
- Statement stmt = null;
- try {
- String jdbcDriver = "jdbc:mysql://localhost:3306/test?Unicode=true&characterEncoding=euckr";
- String dbUser = "root";
- String dbPass = "1234";
- String query = "update member set memberid = '" + name + "' " + "where memberid = '" + memberID + "'";
- conn = DriverManager.getConnection(jdbcDriver, dbUser, dbPass);
- stmt = conn.createStatement();
- updateCount = stmt.executeUpdate(query);
- } catch (SQLException ex) {
- out.println(ex.getMessage());
- ex.printStackTrace();
- } finally {
- if(stmt != null) { try { stmt.close(); } catch(SQLException ex) {} }
- if(conn != null) { try { conn.close(); } catch(SQLException ex) {} }
- }
- %>
- <html>
- <head>
- <title>UpdateName</title>
- </head>
- <Body>
- <% if(updateCount > 0) { %>
- <%=memberID %>의 이름을 <%=name %>으로 변경
- <% } else { %>
- <%=memberID %>아이디가 존재하지 않음
- <% } %>
- </Body>
- </html>
모두 구성했다면 다음의 순서대로 실행해주시면 됩니다.
viewMemberList.jsp -> updateForm.jsp(update.jsp) -> viewMemberList.jsp
* Statement의 executeUpdate() 메서드는 변경된 레코드의 개수를 리턴하는데, where 조건에서 지정한 아이디가 존재하지 않으면 변경되는 레코드가 존재하지 않게 되며 따라서 0을 리턴합니다. 이렇게 변경된 레코드의 개수를 사용하여 지정한 아이디의 존재 여부를 판단할 수 있습니다.
ResultSet에서 값 읽어오기
Statement의 executeQuery() 메서드는 SELECT 쿼리를 실행할 때 사용되며, 결과를 ResultSet 객체에 담아서 리턴합니다.
ResultSet 클래스는 next() 메서드를 제공하는데, 이 메서드를 사용하여 SELECT 결과의 존재 여부를 확인할 수 있습니다.
처음에 커서는 첫번째 행 이전에 위치하고 마지막 행에 도달하면 false 를 리턴합니다.
아래 표는 ResultSet 클래스의 주요 메서드입니다.
getString(String name / int index) |
칼럼의 값을 읽어온다. / 리턴타입 : String, int |
getCharacterStream(String name / int index) |
칼럼의 값을 읽어온다.(LONG VARCHAR 타입) / 리턴타입 : java.io.Reader |
getInt(String name / int index) |
칼럼의 값을 읽어온다. / 리턴타입 : int |
getLong(String name / int index) |
칼럼의 값을 읽어온다. / 리턴타입 : long |
getDouble(String name / int index) |
칼럼의 값을 읽어온다. / 리턴타입 : double |
getFloat(String name / int index) |
칼럼의 값을 읽어온다. / 리턴타입 : float |
getTimestamp(String name / int index) |
칼럼의 값을 읽어온다.(SQL TIMESTAMP 타입) / 리턴타입 : java.sql.Timestamp |
getDate(String name / int index) |
칼럼의 값을 읽어온다.(SQL DATE 타입) / 리턴타입 : java.sql.Date |
getTime(String name / int index) |
칼럼의 값을 읽어온다.(SQL TIME 타입) / 리턴타입 : java.sql.Time |
1개 이상의 행을 처리할 경우 while 구문이나 do-while 구문을 사용하면 됩니다.
▶ while 구문
rs = stmt.executeQuery([쿼리]);
while(rs.next()) {
String name = rs.getString(1);
}
▶ do-while 구문
rs = stmt.executeQuery([쿼리]);
if(rs.next()) {
do {
String name = rs.getString("NAME");
...
} while(rs.next());
}
아래 예제를 통해 확인해보겠습니다.
<RSForm.jsp>
- <%@ page language="java" contentType="text/html; charset=EUC-KR" pageEncoding="EUC-KR"%>
- <html>
- <head>
- <title>MemberIDForm</title>
- </head>
- <body>
- <form action="<%=request.getContextPath() %>/resultSet/viewUsingRS.jsp">
- <table border="1" cellpadding="0" cellspacing="0">
- <tr>
- <td>MEMBERID</td>
- <td><input type="text" name="memberID" size="10"/></td>
- </tr>
- </table>
- <input type="submit" value="확인"/>
- </form>
- </body>
- </html>
<viewUsingRS.jsp>
- <%@ page language="java" contentType="text/html; charset=EUC-KR" pageEncoding="EUC-KR"%>
- <%@ page import="java.sql.DriverManager" %>
- <%@ page import="java.sql.Connection" %>
- <%@ page import="java.sql.Statement" %>
- <%@ page import="java.sql.ResultSet" %>
- <%@ page import="java.sql.SQLException" %>
- <%
- request.setCharacterEncoding("euc-kr");
- String memberID = request.getParameter("memberID");
- %>
- <html>
- <head>
- <title>MemberList</title>
- </head>
- <body>
- <%
- Class.forName("com.mysql.jdbc.Driver");
- Connection conn = null;
- Statement stmt = null;
- ResultSet rs = null;
- try {
- String jdbcDriver = "jdbc:mysql://localhost:3306/test?Unicode=true&characterEncoding=euckr";
- String dbUser = "root";
- String dbPass = "1234";
- String query = "select * from member where memberid = '"+memberID+"' ";
- conn = DriverManager.getConnection(jdbcDriver, dbUser, dbPass);
- stmt = conn.createStatement();
- rs = stmt.executeQuery(query);
- if(rs.next()) {
- %>
- <table border="1" cellpadding="0" cellspacing="0">
- <tr>
- <td>MEMBERID</td>
- <td>PASSWORD</td>
- <td>NAME</td>
- <td>EMAIL</td>
- </tr>
- <tr>
- <td><%=rs.getString("memberid") %></td>
- <td><%=rs.getString("password") %></td>
- <td><%=rs.getString("name") %></td>
- <td><%=rs.getString("email") %></td>
- </tr>
- </table>
- <% } else { %>
- <%=memberID%>에 해당하는 정보가 없습니다.
- <% }
- } catch(SQLException ex) {
- out.println(ex.getMessage());
- ex.printStackTrace();
- } finally {
- if(rs != null) { try { rs.close(); } catch(SQLException ex) {} }
- if(stmt != null) { try { stmt.close(); } catch(SQLException ex) {} }
- if(conn != null) { try { conn.close(); } catch(SQLException ex) {} }
- }
- %>
- </body>
- </html>
실행하면 다음과 같이 출력됩니다.
* LONG VARCHAR 타입의 칼럼은 getCharacterStream() 메서드를 사용하여 읽어오는 것이 원칙이지만, 다수이 JDBC 드라이버는 getString() 메서드를 사용하여 읽어올 수 있도록 하고 있습니다. MySQL 의 경우 getString() 메서드를 사용해서 LONG VARCHAR 타입을 읽을 수 있도록 지원해줍니다.
getString() 메서드를 사용하여 LONG VARCHAR 타입을 읽을 수 있는 경우라면 getString() 메서드를 사용하는 것이 좋습니다.
PreparedStatement를 사용한 쿼리 실행
Statement와 동일한 기능을 제공하지만, 다른 점은 SQL 쿼리의 틀을 미리 생성해 놓고 값을 나중에 지정 한다는 점입니다.
사용순서는 다음과 같습니다.
① Connection.prepareStatement() 메서드를 사용하여 PreparedStatement 생성
② PreparedStatement의 set 메서드를 사용하여 필요한 값 지정
③ PreparedStatement의 executeQuery() / executeUpdate() 메서드를 사용하여 쿼리 실행
④ finally 블록에서 close() 메서드를 사용하여 PreparedStatement를 종료
다음은 사용 형식에 관한 예제입니다.
PreparedStatement pstmt = null;
pstmt = conn.prepareStatement("insert into MEMBER values(?, ?, ?, ?)");
pstmt.setString(1, [value1]);
pstmt.setString(2, [value2]);
pstmt.setString(3, [value3]);
pstmt.setString(4, [value4]);
쿼리 중 값의 부분을 물음표('?')로 사용하는 것을 알 수 있습니다.
PreparedStatement 가 제공하는 set 메서드는 다음과 같습니다.
setString(int index, String value) |
지정한 index의 값을 문자열 value로 지정한다. |
setCharacterStream(int index, Reader reader, int length) |
지정한 index의 파라미터 값을 LONG VARCHAR 타입의 값으로 지정. (readeer는 값을 읽어올 스트림, length는 지정한 문자열의 길이) |
setInt(int index, int value) |
지정한 index의 값을 int 값 value로 지정한다. |
setLong(int index, long value) |
지정한 index의 값을 long 값 value로 지정한다. |
setDouble(int index, double value) |
지정한 index의 값을 double 값 value로 지정한다. |
setFloat(int index, float value) |
지정한 index의 값을 float 값 value로 지정한다. |
setTimestamp(int index, Timestamp value) |
지정한 index의 값을 java.sql.Timestamp 타입의 value로 지정한다. |
setDate(int index, Date value) |
지정한 index의 값을 java.sql.Date 타입의 value로 지정한다. |
setTime(int index, Time value) |
지정한 index의 값을 java.sql.Time 타입의 value로 지정한다. |
PreparedStatement도 다음의 두 메서드를 사용하여 쿼리를 실행합니다. (실행할 쿼리를 미리 지정해놔서 파라미터 값이 없습니다)
▶ ResultSet executeQuery() : SELECT 쿼리 실행 / 결과값을 ResultSet 객체에 저장해서 리턴.
▶ int executeUpdate() : INSERT, UPDATE, DELETE 쿼리 실행 / 변경 또는 삽입된 레코드의 개수를 리턴.
다음 예제를 통해 확인해보겠습니다.
<PSForm.jsp>
- <%@ page language="java" contentType="text/html; charset=EUC-KR" pageEncoding="EUC-KR"%>
- <html>
- <head>
- <title>TableRecordInsert</title>
- </head>
- <body>
- <form action="<%=request.getContextPath() %>/PreparedStatement/viewUsingPS.jsp" method="post">
- <table border="1" cellpadding="0" cellspacing="0">
- <tr>
- <th>MEMBERID</th>
- <td><input type="text" name="memberID" size="10"/></td>
- <th>PASSWORD</th>
- <td><input type="password" name="password" size="10"/></td>
- </tr>
- <tr>
- <th>NAME</th>
- <td><input type="text" name="name" size="10"/></td>
- <th>EMAIL</th>
- <td><input type="text" name="email" size="20"/></td>
- </tr>
- <tr>
- <td colspan="4" align="center">
- <input type="submit" value="INSERT"/>
- </td>
- </tr>
- </table>
- </form>
- </body>
- </html>
<viewUsingPS.jsp>
- <%@ page language="java" contentType="text/html; charset=EUC-KR" pageEncoding="EUC-KR"%>
- <%@ page import="java.sql.DriverManager" %>
- <%@ page import="java.sql.Connection" %>
- <%@ page import="java.sql.PreparedStatement" %>
- <%@ page import="java.sql.SQLException" %>
- <%
- request.setCharacterEncoding("euc-kr");
- String memberID = request.getParameter("memberID");
- String password = request.getParameter("password");
- String name = request.getParameter("name");
- String email = request.getParameter("email");
- Class.forName("com.mysql.jdbc.Driver");
- Connection conn = null;
- PreparedStatement pstmt = null;
- try {
- String jdbcDriver = "jdbc:mysql://localhost:3306/test?unicode=true&characterEncoding=euckr";
- String dbUser = "root";
- String dbPass = "1234";
- conn = DriverManager.getConnection(jdbcDriver, dbUser, dbPass);
- pstmt = conn.prepareStatement("insert into member values(?, ?, ?, ?)");
- pstmt.setString(1, memberID);
- pstmt.setString(2, password);
- pstmt.setString(3, name);
- pstmt.setString(4, email);
- pstmt.executeUpdate();
- } catch(SQLException ex) {
- out.println("Exception Occured!");
- out.println(ex.getMessage());
- } finally {
- if(pstmt != null) { try { pstmt.close(); } catch(SQLException ex) {} }
- if(conn != null) { try { conn.close(); } catch(SQLException ex) {} }
- }
- %>
- <html>
- <head>
- <title>PreparedStatementResult</title>
- </head>
- <body>
- 레코드를 정상적으로 삽입했습니다.
- </body>
- </html>
구성 후 실행을 해보겠습니다.
<viewMemberList.jsp> 파일을 실행해서 결과를 확인해보겠습니다.
PreparedStatement 쿼리를 사용하는 이유
다음과 같은 이유로 사용합니다.
▶ 반복 실행되는 동일한 쿼리의 속도 증가를 위해 (중복된 쿼리분석 제거)
▶ 값 변환을 자동으로 하기 위해
▶ 간결한 코드를 위해 (Statement에서 지정할 값에 따라 쓰이는 따옴표 제거)