📌Statement 와 PreparedStatement의 차이점
Statement |
- statement : 접속된 dbms서버에 sql명령을 전달하여 실행된 결과를 반환하는 기능을 제공하는 인스턴스
- 장점 : 하나의 statement로 다수의 sql명령을 전달하여 실행한다. 즉, statement를 여러개 만들 이유가 없다!
- 단점 : sql명령을 완성할 때 자바변수값을 이용해야하는데, 이것을 sql에 전달해주기 위해서는 결합을 해주어야하는데 간결하지 못하다.(가독성이 떨어진다)
- sql명령어 java 변수값을 포함하고자 할 경우 문자열 결합 가능
=> 문자열 겹합을 이용할 경우 가독성이 낮으며 유지보수에 효율성이 낮음 - 조건이 무조건적인 참이 될 수 있으므로 보안에 취약하다
- InSQL : 값대신 sql명령을 입력하는 공격이다. 이 공격에 아주 취약하다.
preparedStatement |
- 접속된 dbms서버에 sql명령을 저장한 후 전달하여 샐행된 결과를 반환하는 기능을 제공하는 인스턴스
- Connection.preparedStatement(String sql)
: sql명령을 저장하여 전달하는 preparedStatement 인스턴스를 반환하는 메소드이다. - 즉, 위의 메소드에서 sql문이 필요하므로 위의 명령 전에 sql문을 먼저 선언해야한다.
- preparedStatement인스턴스에 저장되는 sql명령에 ? (Inparameter)를 사용할 수 있다.
- Inparameter : Java변수값을 제공받아 오라클상수로 sql명령의 값으로 표현하기 위한 do?다.
- 모든 Inparameter에 java변수값이 전달되어야만 sql명령이 완성된다!!
- PreparedStatement.setXXX(int parameterIndex, XXX value)
: 원하는 위치의 Inparameter에 원하는 값을 전달하기 위한 메소드이다.
- 이 메소드는 Inparameter의 갯수만큼 호출되어야 한다. - PreparedStatement.executeUpdate()
: preparedStatement 인스턴스에 저장된 sql명령을 전달하는 메소드 (조작행의 갯수를 반환) - sql명령이 여러개이면 pstmt도 여러개 있어야 한다.
- PreparedStatement.executeQuery()
: 검색결과를 반환 - 장점
1. sql명령에 Inparameter를 사용하여 값을 전달받아 작성한다.
2. Inparameter를 사용하여 가독성과 유지보수가 좋아진다. - 단점
1. 하나의 sql명령만 전달이 가능하다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class PreparedStatementApp {
public static void main(String[] args) throws IOException, SQLException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
// 키보드로 학생정보를 입력받아 저장
System.out.println("<<학생정보 입력>>");
System.out.print("학번 입력 >> ");
int no = Integer.parseInt(in.readLine());
System.out.print("이름 입력 >> ");
String name = in.readLine();
System.out.print("전화번호 입력 >> ");
String phone = in.readLine();
System.out.print("주소 입력 >> ");
String address = in.readLine();
System.out.print("생년월일 입력 >> ");
String birth = in.readLine();
Connection con = ConnectionFactory.getConnection();
String sql = "insert into student values(?,?,?,?,?)";
PreparedStatement pstmt = con.prepareStatement(sql);
pstmt.setInt(1, no);
pstmt.setString(2, name);
pstmt.setString(3, phone);
pstmt.setString(4, address);
pstmt.setString(5, birth);
int rows = pstmt.executeUpdate();//stmt와 달리 sql명령을 전달하지 않는다.
System.out.println("[결과]" + rows+ "명의 학생정보를 입력하였습니다.");
System.out.println("=======================================================");
String sql2 = "select * from student order by no";
pstmt = con.prepareStatement(sql2);
ResultSet rs = pstmt.executeQuery();
System.out.println("<<학생목록>>");
while(rs.next()) {
System.out.println("학번 = " + rs.getInt(1));
System.out.println("이름 = " + rs.getString(2));
System.out.println("전화번호 = " + rs.getString(3));
System.out.println("주소 = " + rs.getString(4));
System.out.println("생년월일 = " + rs.getString(5));
}
System.out.println("=======================================================");
String sql3 = "select * from student where name = ? order by no";
pstmt = con.prepareStatement(sql3);
System.out.print("이름 입력 >> ");
String name2 = in.readLine();
pstmt.setString(1, name2);
rs = pstmt.executeQuery();
System.out.println("<<학생목록>>");
while(rs.next()) {
System.out.println("학번 = " + rs.getInt(1));
System.out.println("이름 = " + rs.getString(2));
}
if(rs != null) rs.close();
if(pstmt != null) pstmt.close();
if(con != null) con.close();
}
}
📌CallableStatement
- 저장프로시저 저장함수를 호출하는 명령을 저장한 후 전달하기 위한 인스턴스이다.
- {call 프로시저명(값,....)} : 저장프로시저를 호출하는 명령
- 저장 프로시저 호출 명령은 execute()메소드를 이용하여 전달
- Connection.prepareCall(String sql)
:저장 프로시저 호출 명령을 저장한 CallableStatement인스턴스를 반환하는 메소드
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;
public class CallableStatementApp {
public static void main(String[] args) throws NumberFormatException, IOException, SQLException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
System.out.println("<<학생정보>>");
System.out.print("학번입력 >>");
int no = Integer.parseInt(in.readLine());
System.out.println("======================================================");
Connection con = ConnectionFactory.getConnection();
//학번을 전달받아 student테이블의 학생정보를 삭제하는 저장 프로시저
/*CREATE OR REPLACE PROCEDURE DELETE_STUDENT(VNO IN NUMBER) IS
BEGIN
DELETE FROM STUDENT WHERE NO = VNO;
COMMIT;
END;
/*/
//CallableStatement : 저장프로시저 저장함수를 호출하는 명령을 저장한 후
//전달하기 위한 인스턴스
//=>값대신 Inparameter사용이 가능함 - Inpatameter에 변수값 또는 변수 전달
//=>저장 프로시저 호출 명령은 execute()메소드를 이용하여 전달
String sql = "{call delete_student(?)}";
CallableStatement cstmt = con.prepareCall(sql);
cstmt.setInt(1, no);
cstmt.execute();//실행
System.out.println("[결과] 학생정보를 삭제하였습니다.");
ConnectionFactory.close(con, cstmt);
}
}
📌DBCP(DataBase Connection Pool)
- Connection인스턴스를 미리 여러 개 생성 저장하여 제공하는 기능의 클래스
- free벡터에 미리 Connection을 담아두었다가 어떤 Connection을 사용하려면 used 벡터로 옮긴다.
- 반대로 사용완료되면 다시 free벡터로 옮기도록 한다.
#Comment
#properties file >> Configuration File
#Key = value
id = abc123
name = \uD64D\uAE38\uB3D9
password = 12345
package site.itwill.dbcp;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
//프로그램 실행에 필요한 값을 제공하기 위한 텍스트 파일
//프로그램을 변경하지 않고 properties파일의 내용을 변경하여 프로그램실행결과를 변경할 수 있다.
//유지보수의 효율성 증가
//properies파일로 제공되는 값은 문자열만 가능
//user.properties파일을 읽어 제공된 값을 반환받아 출력하는 프로그램
public class PropertiesApp {
public static void main(String[] args) throws IOException {
//properties파일을 읽기 위한 입력스트림 생성
//FileInputStream클래스를 이용하여 입력스트림을 생성
//=> 파일경로에 대한 문제가 발생할 수 있음
//InputStream in = new FileInputStream("bin/site/itwill/dbcp/user.properties");
//리플렉션 기능을 이용하여 입력스트림 생성
//-> 클래스.class : 메모리에 저장된 클래스를 직접 표현하여 사용하는 방법 => clazz
//Class.getClassLoader() : 클래스로더 인스턴스를 반환하는 메소드이다.
//ClassLoader.getResourceAsStream()
//리소스 파일 경로를 전달하여 파일을 읽기 위한 입력스트림을 생성하여 반환하는 메소드
InputStream in = PropertiesApp.class.getClassLoader().getResourceAsStream("site/itwill/dbcp/user.properties");
//properties인스턴스 생성
//Properties : map인터페이스를 상속받은 콜렉션 클래스
Properties properties = new Properties();
//properties파일을 읽어 properties인스턴스에 저장
//=> Properties파일의 한 레코드를(key = value) 하나의 엔트리(Entry : 하나의 쌍으로 묶어져 있는 값들.)로 저장
//Properties.load(InputStream in) : 입력스트림으로 properties파일을 읽어 properties 인스턴스에 저장하는 메소드
properties.load(in);
//propertis인스턴스에 저장된 엔트리중 원하는 값을 Key를 이용하여 반환받아 저장
//Properties.get(String key) : 키에 대한 값을 반환하는 메소드
//=> 값이 오브젝트 타입으로 반환하므로 객체 형변환하여 저장
String id = (String) properties.get("id");
String password = (String)properties.get("password");
String name = (String)properties.get("name");
System.out.print("저장된 내용 >> ");
System.out.println("아이디 = " + id);
System.out.println("비번 = " + password);
System.out.println("이름 = " + name);
}
}
package site.itwill.dbcp;
import java.sql.Connection;
import java.sql.SQLException;
//DBCP(DataBase Connection Pool) : Connection인스턴스를 미리 여러개 생성 저장하여 제공하는 기능의 클래스
//필요할때마다 만드는게 아니라, 미리 만들어놓고 쓰는거
public class ConnectionPoolApp {
public static void main(String[] args) throws SQLException {
//ucp <- javax.sql <- DataSource를 상속받아서 만들어짐
//ConnectionPool인스턴스에는 미리 Connection인스턴스가
ConnectionPool cp = ConnectionPool.getInstance();
Connection con1 = cp.getConnection();
System.out.println("con1 = " + con1);
cp.freeConnection(con1);//다시 돌려준다
Connection con2 = cp.getConnection();
System.out.println("con2 = " + con2);
cp.freeConnection(con2);//다시 돌려준다
Connection con3 = cp.getConnection();
System.out.println("con3 = " + con3);
cp.freeConnection(con3);//다시 돌려준다
}
}
package site.itwill.dbcp;
import java.sql.Connection;
import java.sql.SQLException;
import oracle.ucp.jdbc.PoolDataSource;
import oracle.ucp.jdbc.PoolDataSourceFactory;
//javax.sql.DataSource : DBCP 클래스를 작성하기 위해 상속받아야 되는 인터페이스
// => DBCP 클래스에 동일한 형태의 메소드 선언되도록 메소드 작성 규칙 제공
//UCP(Universal Connection Pool) 라이브러리의 PoolDataSource 인스턴스를 이용한 JDBC 프로그램
public class PoolDataSourceApp {
public static void main(String[] args) throws SQLException {
//PoolDataSourceFactory.getPoolDataSource() : PoolDataSource 인스턴스를 생성하여 반환하는 메소드
//PoolDataSource : DBCP 기능을 제공하는 인스턴스
PoolDataSource pds=PoolDataSourceFactory.getPoolDataSource();
//Connection 인스턴스를 생성하기 위해 PoolDataSource 인스턴스의 필드값 변경
pds.setConnectionFactoryClassName("oracle.jdbc.driver.OracleDriver");
pds.setURL("jdbc:oracle:thin:@localhost:1521:xe");
pds.setUser("scott");
pds.setPassword("tiger");
//Connection 인스턴스의 갯수를 제한하기 위해 PoolDataSource 인스턴스의 필드값 변경
// => Connection 인스턴스의 갯수를 제한하지 않을 경우 기본값 사용
pds.setInitialPoolSize(2);
pds.setMaxPoolSize(3);
//PoolDataSource.getConnection() : Connection 인스턴스를 반환하는 메소드
// => PoolDataSource 인스턴스에 미리 생성된 Connection가 없는 경우 생성하여 저장
Connection con1=pds.getConnection();
System.out.println("con1 = "+con1);
System.out.println("사용 가능한 Connection 인스턴스 갯수 = "
+pds.getAvailableConnectionsCount());
//Connection 인스턴스를 제거하면 자동으로 PoolDataSource 인스턴스는
//새로운 Connection 인스턴스를 생성하여 추가 - Connection 인스턴스의 갯수 유지
//con1.close();
System.out.println("사용 가능한 Connection 인스턴스 갯수 = "
+pds.getAvailableConnectionsCount());
System.out.println("===============================================");
Connection con2=pds.getConnection();
System.out.println("con2 = "+con2);
//con2.close();
System.out.println("===============================================");
Connection con3=pds.getConnection();
System.out.println("con3 = "+con3);
//con3.close();
System.out.println("===============================================");
Connection con4=pds.getConnection();
System.out.println("con4 = "+con4);
con4.close();
System.out.println("===============================================");
}
}
'💻 수업정리 (2020) > 오라클' 카테고리의 다른 글
[7/2] DAO와 DTO 클래스, 정규표현식 사용해보기 (0) | 2020.07.02 |
---|---|
[6/30]ConnectionFactory와 ResultSet커서 이용 (0) | 2020.06.30 |
[6/29]JDBC연동 ( + 리플랙션에 대해서 알아두기) (0) | 2020.06.29 |
[6/26] 객체권한, 저장프로시저, 트리거 (0) | 2020.06.26 |
[6/25] 인라인뷰와 시퀀스, 권한 부여 (0) | 2020.06.25 |