jdbc - preparedStatement

jinkyung·2021년 1월 15일
0

DBMS

목록 보기
19/21

preparedStatement

package ex01.jdbcp.pstmt;

import java.sql.*;
/*
Statement 
 - 실행시 sql문을 받아서 오라클 서버에 전송하기 알맞은 형태로 변환해서 전송한다.
PreparedStatement
 - 객체 생성시 sql문을 받아서 미리 알맞은 형태로 변환하고 전송하기 직전에 
   ? 부분만 변수 값으로 받아서 전송한다.
 - sql 문의 구조는 동일하되 파라미터 값만 변경될 때 Statement 보다 속도가 빠르다. 
  왜냐하면 객체 생성시 미리 sql문의 구조를 최적화 해놨기 때문이다.
  그래서 파라미터만 변경되고 sql문의 구조는 미리 최적화 해놓은 그대로 상태를 재활용하므로 
  속도가빠를 수 밖에 없다. 
*/

public class PrepareStatementEx {
	// 1. 오라클 접속에 필요한 클래스를 메모리로 로딩한다
	static {
		try { // class not found exception 해결을 위해 try catch문으로 감싼다.
			Class.forName("oracle.jdbc.driver.OracleDriver");
		} catch (ClassNotFoundException e) {

			e.printStackTrace();
		}
	}

	public static void main(String[] args) {

		// 2. url, id, pass
		String url = "jdbc:oracle:thin:@localhost:1521:xe";
		String id = "bitTest";
		String pass = "bitTest";

		// 3. 클래스 변수 선언
		Connection con = null; // 오라클 접속에 필요
		PreparedStatement preStmt = null; // SQL문 실행에 필요
		ResultSet rs = null; // Select문 결과값 저장에 필요

		try {
			// 4. 오라클 접속
			con = DriverManager.getConnection(url, id, pass);

			// 5. 테이블 생성
			String strCreate = "CREATE TABLE student (\n" 
                    + "  sno varchar2(8) PRIMARY KEY, \n"
					+ "  sname varchar2(10),\n" 
                    + "  sex varchar2(3),\n" 
                    + "  syear number(1),\n"
					+ "  major varchar2(10),\n" + "  avr number(4,2)\n" + ")";

			preStmt = con.prepareStatement(strCreate);
			int cnt = preStmt.executeUpdate();
			System.out.println("결과값 : " + cnt);

			// 6. 데이터 삽입
			String strInsert = "INSERT INTO student (sno, sname, sex, syear, major, avr) 
                                 VALUES (?,?,?,?,?,?)";
			preStmt = con.prepareStatement(strInsert);
			// '915301','공융','남',4,'화학',0.95 물음표는 밑에 넣은 값들로 채워진다.
			preStmt.setString(1, "915301");
			preStmt.setString(2, "공융");
			preStmt.setString(3, "남");
			preStmt.setInt(4, 4);
			preStmt.setString(5, "화학");
			preStmt.setDouble(6, 0.95);

			cnt = preStmt.executeUpdate();
			System.out.println(cnt + "개 행 적용");

			// 7. 결과 검사
			String strSelect = "SELECT * FROM student";
			preStmt = con.prepareStatement(strSelect);
			rs = preStmt.executeQuery();
			int idx = 1;
			while (rs.next()) {       //rs는 next를 실행하는 순간 첫번째를 가리키게 된다.
				System.out.println("--------[ " + idx + " ]---------");
				System.out.println("sno : " + rs.getString(1));
				System.out.println("sname : " + rs.getString(2));
				System.out.println("sex : " + rs.getString(3));
				System.out.println("syear : " + rs.getInt(4));
				System.out.println("major : " + rs.getString(5));
				System.out.println("avr : " + rs.getDouble(6));
				idx++;
			}

		
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				// 8. 열린 객체 모두 닫기 , finally는 정상실행이든 예외가 발생하든 무조건 처리해준다.
				// null이 아니라는 것은 정상실행되었다는 것이므로 닫아라.
				if (rs != null) rs.close();
				if (preStmt != null) preStmt.close();
				if (con != null) con.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

차이점

statement는 update할 때 객체 넣음

Statement statemt = con.createStatement();  //Statement 객체 생성
String strInsert = "INSERT INTO emp (eno, ename) " + "\r\n" + 
					"VALUES ('9000', '홍길동')";
int cnt = statemt.executeUpdate(strInsert); // 이때 insert 객체를 넣음

그런데 prepared statement는

String strInsert = "INSERT INTO student (sno, sname, sex, syear, major, avr) VALUES (?,?,?,?,?,?)";
preStmt = con.prepareStatement(strInsert); //preStmt 객체를 생성하면서 객체를 넣음

처럼 객체 생성시에 sql문을 넣어주어 최적화시킨다. (구조 최적화)

---> 반복작업 시에 속도 차이가 난다.

예를 들어

"INSERT INTO student (sno, sname, sex, syear, major, avr)

VALUES (?,?,?,?,?,?)"

처럼 구조의 틀이 미리 들어가있고 값만 넣어주어 바꾸면 되기 때문에 preStmt가 더 빠른 것이다.


  • for문으로 반복작업 예시를 들었다.
package ex01.jdbcp.pstmt;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class PreparedStatementInsert {

	static {
		try { 
			Class.forName("oracle.jdbc.driver.OracleDriver");
		} catch (ClassNotFoundException e) {

			e.printStackTrace();
		}
	}

	public static void main(String[] args) {

		// 2. url, id, pass
		String url = "jdbc:oracle:thin:@localhost:1521:xe";
		String id = "bitTest";
		String pass = "bitTest";

		// 3. 클래스 변수 선언
		Connection con = null; // 오라클 접속에 필요
		PreparedStatement preStmt = null; // SQL문 실행에 필요
		ResultSet rs = null; // Select문 결과값 저장에 필요
		int cnt = 0 ;
		
		try {
			// 4. 오라클 접속
			con = DriverManager.getConnection(url, id, pass);

			
//			아래처럼 sql문의 기본 구조는 동일하고 
//			?를 대신할 파라미터만 계속 변경되므로 
//			이럴 경우 Statement보다 월등히 속도가 빠르다.
			
			// 5. 데이터 삽입
			String strInsert = "INSERT INTO student (sno, sname, sex, syear, major, avr) VALUES (?,?,?,?,?,?)";
			preStmt = con.prepareStatement(strInsert);
			
			for (int i = 0; i < 1000; i++) {
				preStmt.setString(1, ""+i);    //i.toString() 이렇게 해도 문자열이 되어 들어감.(pk는 중복되면 안되니까 바꿔줌)
				preStmt.setString(2, "공융");
				preStmt.setString(3, "남");
				preStmt.setInt(4, 4);
				preStmt.setString(5, "화학");
				preStmt.setDouble(6, 0.95);	
			}
			

			cnt = preStmt.executeUpdate();
			System.out.println(cnt + "개 행 적용");

			// 6. 결과 검사
			String strSelect = "SELECT * FROM student";
			preStmt = con.prepareStatement(strSelect);
			rs = preStmt.executeQuery();
			int idx = 1;
			while (rs.next()) { // next를 실행하는 순간 첫번째를 가리키게 된다.
				System.out.println("--------[ " + idx + " ]---------");
				System.out.println("sno : " + rs.getString(1));
				System.out.println("sname : " + rs.getString(2));
				System.out.println("sex : " + rs.getString(3));
				System.out.println("syear : " + rs.getInt(4));
				System.out.println("major : " + rs.getString(5));
				System.out.println("avr : " + rs.getDouble(6));
				idx++;
			}

		
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				// 7. 열린 객체 모두 닫기 , finally는 정상실행이든 예외가 발생하든 무조건 처리해준다.
				// null이 아니라는 것은 정상실행되었다는 것이므로 닫아라.
				if (rs != null) rs.close();
				if (preStmt != null) preStmt.close();
				if (con != null) con.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

  • 순서대로 데이터가 저장되지 않는 이유?

동시다발적으로 들어갈때 먼저보낸 것에 정체가 일어나거나.. 해서 순서가 바껴 들어갈 수 있다.

혹은 오라클 DB는 행의 순서와 무관하니까.. 무작위로 저장될 수도 있다.

order by를 통해 콘솔창에 순서대로 검색결과를 보여준다.

Thread.sleep의 시간을 더 주면 순서대로 들어갈까..?

package ex01.jdbcp.pstmt;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class PreparedStatementInsert {

	static {
		try { 
			Class.forName("oracle.jdbc.driver.OracleDriver");
		} catch (ClassNotFoundException e) {

			e.printStackTrace();
		}
	}

	public static void main(String[] args) {

		// 2. url, id, pass
		String url = "jdbc:oracle:thin:@localhost:1521:xe";
		String id = "bitTest";
		String pass = "bitTest";

		// 3. 클래스 변수 선언
		Connection con = null; // 오라클 접속에 필요
		PreparedStatement preStmt = null; // SQL문 실행에 필요
		ResultSet rs = null; // Select문 결과값 저장에 필요
		int cnt = 0 ;
		
		try {
			// 4. 오라클 접속
			con = DriverManager.getConnection(url, id, pass);

			
//			아래처럼 sql문의 기본 구조는 동일하고 
//			?를 대신할 파라미터만 계속 변경되므로 
//			이럴 경우 Statement보다 월등히 속도가 빠르다.
			
			// 5. 데이터 삽입
			String strInsert = "INSERT INTO student (sno, sname, sex, syear, major, avr) VALUES (?,?,?,?,?,?)";
			preStmt = con.prepareStatement(strInsert);
			
			for (int i = 0; i < 1000; i++) {
				preStmt.setString(1, ""+i);    //i.toString() 이렇게 해도 문자열이 되어 들어감.(pk는 중복되면 안되니까 바꿔줌)
				preStmt.setString(2, "공융");
				preStmt.setString(3, "남");
				preStmt.setInt(4, 4);
				preStmt.setString(5, "화학");
				preStmt.setDouble(6, 0.95);	
				
				cnt = preStmt.executeUpdate();
				System.out.println(cnt + "개 행 적용");
				//Thread.sleep(10);  하나 보낼때마다 10ms(==0.01초)씩 쉬었다가 전송된다. 
			}

			// 6. 결과 검사
			String strSelect = "SELECT * FROM student ORDER BY TO_NUMBER(sno)";
			preStmt = con.prepareStatement(strSelect);
			rs = preStmt.executeQuery();
			int idx = 1;
			while (rs.next()) { // next를 실행하는 순간 첫번째를 가리키게 된다.
				System.out.println("--------[ " + idx + " ]---------");
				System.out.println("sno : " + rs.getString(1));
				System.out.println("sname : " + rs.getString(2));
				System.out.println("sex : " + rs.getString(3));
				System.out.println("syear : " + rs.getInt(4));
				System.out.println("major : " + rs.getString(5));
				System.out.println("avr : " + rs.getDouble(6));
				idx++;
			}

		
		} catch (SQLException e) {
			e.printStackTrace();
//		} catch (InterruptedException e){       -- thread로 인한 exception
//			e.printStackTrace();
		}finally {
			try {
				// 7. 열린 객체 모두 닫기 , finally는 정상실행이든 예외가 발생하든 무조건 처리해준다.
				// null이 아니라는 것은 정상실행되었다는 것이므로 닫아라.
				if (rs != null) rs.close();
				if (preStmt != null) preStmt.close();
				if (con != null) con.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

0개의 댓글