221205 오라클 : java와 오라클 연동(JDBC)
JDBC
Java database connectivity
java 프로그램 안에서 SQL을 실행하기 위해서 데이터베이스를 연결해주는 응용프로그램 인터페이스
(자바 API / 자바가 제공하는 표준 인터페이스)
JDBC를 사용하면 다른 관계형 데이터베이스에서도 SQL을 사용하기 쉽다. 데이터베이스 응용업무
(Sybase, Oracle, Informix, mSQL 등 따로 만들 필요가 없다.)
1번 방법
1. jdbc 드라이버 설치
- jdbc 드라이버 파일 오라클설치 폴더에 있음.
c드라이브 oraclexe - product - 서버 -jdbc - ojdbc.jar파일(자바용 압축파일)
자바에서 해당파일을 실행 가능
ojdbc5 (1.4 이하버전)
ojdbc6 (1.6 이상)
ojdbc6_g (모바일)
- 자바 설치 폴더에 해당파일 복사
바탕화면에 ojdbc6 복붙
1) D:\B_Util\2.Java\JDK1.8\jre\lib\ext
에 ojdbc6 붙여넣기
2번 방법 - 가장 많이 사용하는 방법
2)- 프로젝트 생성후 library에 등록
(1) 프로젝트 생성
Open perspective- 자바선택
new 자바 프로젝트 생성 제목 : DBPROC
Properties - java Build Path - Libraries - ojdbc6
NEW CLASS 생성
Class 생성
1. DBTest
2. OracleTest
3. StateTest
▶ DBTest : 오라클 SQL 연결
1) import
import java.sql.Connection; // 연결객체 생성
import java.sql.DriverManager; // JDBC 드라이버 로딩 및 세트 관리
import java.sql.SQLException; // 예외처리
JDBC 에서 사용하는 객체
2) DriverManager 클래스 : 드라이버 로드
- 데이터 원본에 JDBC 드라이버로 Connection을 받음.
- Class.forName() 메소드 호출로 생성 및 DriverManager 에 등록
- DriverManager 클래스는 모두 static으로 반드시 객체를 생성시킬 필요는 없다.
- Connection 인터페이스를 구현(객체생성)시키기 위해 getConnection() 메서드를 호출한다.
- 드라이버 클래스를 찾지 못할 경우 ClassNotFoundException 예외를 생성시킨다.
=> 예외처리
3) Connection 인터페이스: DB연결
- DB 원본에 연결하기 위해 Connection 인터페이스 구현(Connection 객체 생성)
4) SQLException 클래스 : 예외처리
- 애플리케이션 실행하는 동안 발생하는 예외 처리의 기본 클래스이다.
- 오류의 특정정보 반환
- getMessage()로 예외 전체 텍스트 반환
- catch 문에 (ClassNotFoundException e) 안쓰고 싶으면 메인메소드 옆에
throws ClassNotFoundException 쓰기
// DB와 연동하기 위해서는 import 반드시 써줘야함.
import java.sql.Connection; // 연결객체 생성
import java.sql.DriverManager;
import java.sql.SQLException;
class DBtest { //dbConnection()는 static 이므로 객체를 생성하지 않아도 쓸수 있다.
public static Connection dbConnection() {
// 오라클 계정은 변수선언 사용해서 자주 쓰면 좋다.
String driver="oracle.jdbc.driver.OracleDriver"; //고정된 값
String url="jdbc:oracle:thin:@localhost:1521:xe"; // 로컬 번호
String userid="LHY93";
String passwd="java";
Connection conn=null;
//try-catch
try {
//1. try에서 드라이버 파일 로딩
Class.forName(driver); // = oracle.jdbc.driver.OracleDriver
//2. 연결객체 생성 : 로컬번호,계정id,계정pw
conn=DriverManager.getConnection(url,userid,passwd);
System.out.println("성공적으로 DB에 연결되었습니다.");
// 예외 클래스 생성
} catch (ClassNotFoundException e) {
System.out.println("Db Dirver 로딩 실패");
// DriverManager의 reference Libraries-ojdbc6 파일 못찾을때
} catch(SQLException e) {
System.out.println("DB 연결 실패");
// Connection 객체 생성에 실패 conn=DriverManager.getConnection의 예외처리
} catch(Exception e) {
System.out.println("오류발생");
e.printStackTrace();
}
return conn; // 갖고있는 값 반환
}
}
※ 싱글톤(Singleton) : 객체의 인스턴스가 오직 1개만 생성되는 패턴.
참조변수가 아무리 많이 생성되어도 객체는 하나만 생성되게 한다.
생성자가 반드시 private이여야 한다. 내부에서 한번만 생성시키도록
▶ OracleTest: Statement 객체생성 및 SQL 질의
1) import
import java.sql.Connection;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.PreparedStatement;
2-1) Statement 인터페이스 (비효율적) - 정적쿼리
- Connection 객체를 통해 CreateStatement() 메서드로 Statement 객체를 생성
- Statement 객체 생성후 executeQuery()메소드로 SQL문 실행 가능 (String으로 전달)
- 반드시 try-catch 문 또는 throw를 통해 예외처리 해줘야함.
- 단순한 질의문을 사용할 경우에 좋음
2-2) Statement 객체의 동작
- 구문분석- 문법검사, 의미검사, 권한검사, 실행계획
- 치환(bind) - 값을 입력 받아 변수에 할당
- 실행(execute) - 디스크에서 데이터를 찾아 버퍼에 복사
- 인출(patch) - 데이터 블록에서 원하는 데이터를 찾아 추출하는 과정
2-3) Statement 객체의 제한(문제점)
ex) String sql="select * from member where mem_id= " +id +
"and mem_pass = " + passwd;
만약 사용자가 id에 "1"을 입력하면 sql은
"select * from member where mem_id= 1" and mem_pass = " + passwd;
만약 사용자가 id에 "1"eotls "1 OR 1=1 --"을 입력하면 sql은
"select * from member where mem_id= OR 1=1--" and mem_pass = " + passwd;
=> '--'는 주석이므로 "--" 이후는 모두 무시됨 => Statement 객체는
SQL Injection에 취약함
- Statement 객체는 객체마다 1개의 ResultSet 객체만이 동시에 오픈되어 사용
2-4) PreparedStatement 인터페이스 (효율적) - 동적 쿼리
- Connection객체를 통해 prepareStatement() 메서드로 prepareStatement객체를 생성
- 한번 분석되면 재사용에 효율적이다.
- SQL 문장이 미리 컴파일 되고, 실행시간동안 인수 값을 위한 공간을 확보할 수 있다.
- 캐시사용
(사용형식)
.SQL 작성시 변수에 할당할 부분에 "?"를 사용하여 쿼리 작성
ex) insert into lprod(lprod_id,lprod_gu,lprod_nm) values(?, ?, ?);
. 이 "?"가 들어간 자리에 set ~ 메서드를 이용하여 값을 할당
객체명.setInt(1,변수명1); --'1'은 첫 번째 '?'와 매핑
객체명.setString(2, 변수명2); --'2'은 두 번째 '?'와 매핑
:
. set~메서드의 종류
setInt(idx,int) -- idx 인덱스를 정수형(int)으로 지정
setString(idx,String) -- idx 인덱스를 String으로 지정
setCharacter(idx,Reader,int) -- idx 인덱스의 파라메터 값을 long 타입으로 지정(인덱스,읽어올 스트림,길이)
오라클의 long VARCHAR 타입 (문자열)
setLong(idx,long) -- idx 인덱스를 long으로 지정
setTime(idx,Time) -- idx 인덱스를 java.sql.Time 타입으로 지정
3) ResultSet 인터페이스
- 커서(cursor)를 가지고 있음.
- SQL문에서 SELECT 문을 사용한 질의의 결과물로 반환
- 질의에 의해 생성된 테이블.
- 메소드 사용으로 커서의 위치를 옮길수 있다. next() : 다음행 ~
- 반복문(while) 사용할 때 next() 에 다음 행이 없다면 false / 있으면 true
4) 질의 수행
ResultSet rs = stmt.executeQuery("수행문");
stmt.execute("qurey");
stmt.executeQurey("qurey"); // select 문 수행
stmt.executeUpdate("qurey"); // insert, update, delete 수행
5) ResultSet 결과 받기 : while문
while(rs.next()) 더이상 읽어올 값이 없으면 false가 되고 while문을 빠져나온다.
while(rs.next()) { // 한 행씩 값 읽기.
int lid=rs.getInt(1); // 컬럼1 : index값 오라클은 첫번째 자리가 1번 부터 이다.
String lgu=rs.getString(2); //컬럼2
String lnm=rs.getString(3); // 컬럼3
String res=lid + lgu + lnm;
System.out.println(res);
}
6) Close
- 가장 최근에 생성된 객체부터 닫아주기
: ResultSet -> Statement / PreparedStatement -> Connection
- try-catch의 마지막으로 finally : 예외가 발생하던 안하던 반드시 수행한다.
finally {
try {
if(rs != null) {rs.close();}
if(stmt != null) {stmt.close();}
if(conn != null) {conn.close();}
}
▶ 전체 OracleTest
import java.sql.Connection;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.PreparedStatement;
public class OracleTest {
public static void main(String[] args) {
Connection conn=null; // DBtest클래스에서 반환되는 값
Statement stmt=null;
ResultSet rs=null;
try {
String sql="select * from lprod"; // 수행시킬 문자열 선언
conn=DBtest.dbConnection(); // static Connection 타입의 메서드 호출 (conn)
stmt=conn.createStatement(); // Statement 객체 생성
rs=stmt.executeQuery(sql); // executeQuery : select 문을 수행
/*lprod 오라클에서 정의된 타입 불러오기
* lprod_id number(7) => int (소숫점이하가 없다 = 정수 int타입)
* lprod_gu varchar2(4) => String
* lprod_nm varchar2(40) => String
*/
// rs에는 lprod_id | lprod_gu | lprod_nm의 값을 불러온다. 한 행 전체를 가져온다.
System.out.println("순번 분류코드 분류명");
System.out.println("==========================================");
while(rs.next()) {
int lid=rs.getInt(1); // 컬럼1 : index값 오라클은 첫번째 자리가 1번 부터 이다.
String lgu=rs.getString(2); //컬럼2
String lnm=rs.getString(3); // 컬럼3
String res=lid + " " + lgu +" " + lnm;
System.out.println(res);
}
} catch(SQLException e) {
System.out.println("오류발생");
e.printStackTrace();
} finally {
try {//예외가 발생될수 있는 명령이나. 필요한 명령어들// 강요되어진 try-catch = sql문
if(rs != null) {rs.close(); }
if(stmt != null) {stmt.close();}
if(conn != null) {conn.close();}
}
catch(Exception e) {
throw new RuntimeException(e.getMessage()); // throw 해당위치에서 오류를 강제로 발생시킨다.
// 생성자 메소드 익명블록. 객체 참조변수가 없다. 이번만 예외객체를 발생시킴..
}
}
}
}
// finally는 반드시 안써도 된다. 오류가 발생하던 안하던 반드시 실행되어야 한다.
▶ Statement / PreparedStatement Test
1) Statement 인 경우
String sql = 안에 단따옴표 ' ' 꼭 써줘야 함.
String sql="insert into lprod(lprod_id,lprod_gu,lprod_nm) values('lid ','lgu','lnm')"
※ int result 왜 int 타입인지?
명령을 실행하고 반환되는 값이 (정수)
성공 : 1
실패 : 1이 아닌 값 (0)
public class StateTest {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
Statement stmt=null;
PreparedStatement pstmt = null;
ResultSet rs=null;
System.out.print("순번 입력 : ");
int lid=sc.nextInt();
System.out.print("분류코드 입력 : ");
String lgu=sc.next();
System.out.print("분류명 입력 : ");
String lnm=sc.next();
Connection conn=DBtest.dbConnection();
try {
String sql="insert into lprod(lprod_id,lprod_gu,lprod_nm) values('"
+ lid + "', '" + lgu + "', '" + lnm + "')";
System.out.println(sql);
stmt=conn.createStatement();
int result=stmt.executeUpdate(sql);
if(result==1) { // 1 : 성공
System.out.println("분류코드가 입력되었습니다...");
} else { // 1 이외의 값 : 실패
System.out.println("분류코드 입력이 실패하였습니다.");
}
} catch (Exception e) {e.printStackTrace();}
finally {
try {
if(rs !=null) {rs.close();}
if(stmt !=null) {stmt.close();}
if(conn != null) {conn.close();}
} catch (Exception e) { }
}
}
}
2) PreparedStatement 인 경우
String sql="insert into lprod(lprod_id,lprod_gu,lprod_nm) values(?,?,?)";
객체명.set~메서드로 '?'의 값 할당
- set~메서드의 종류 -
setInt(idx,int) : idx 인덱스를 정수형(int)으로 지정
setString(idx,String) : idx 인덱스를 String으로 지정
setCharacter(idx,Reader,int) : idx 인덱스의 파라메터 값을 long 타입으로 지정(인덱스,읽어올 스트림,길이)
오라클의 LONG VARCHAR 타입 (문자열)
setLong(idx,long) : idx 인덱스를 long으로 지정
setFloat(idx,float) : idx 인덱스를 float으로 지정
setDouble(idx,double) : idx 인덱스를 double으로 지정
setTime(idx,Time) : idx 인덱스를 java.sql.Time 타입으로 지정
public class StateTest {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
Statement stmt=null;
PreparedStatement pstmt = null;
ResultSet rs=null;
System.out.print("순번 입력 : ");
int lid=sc.nextInt();
System.out.print("분류코드 입력 : ");
String lgu=sc.next();
System.out.print("분류명 입력 : ");
String lnm=sc.next();
Connection conn=DBtest.dbConnection();
try {
String sql="insert into lprod(lprod_id,lprod_gu,lprod_nm) values(?,?,?)";
pstmt = conn.prepareStatement(sql); //prepareStatement 객체 생성
pstmt.setInt(1, lid); // 첫번째 '?' : 순번(정수)
pstmt.setString(2, lgu); // 두번째 '?' : 분류코드(String)
pstmt.setString(3,lnm); // 세번째 '?' : 분류명(String)
int result = pstmt.executeUpdate();
if(result==1) { // 1 : 성공
System.out.println("분류코드가 입력되었습니다...");
} else { // 1 이외의 값 : 실패
System.out.println("분류코드 입력이 실패하였습니다.");
}
} catch (Exception e) {e.printStackTrace();}
finally {
try {
if(rs !=null) {rs.close();}
if(stmt !=null) {stmt.close();}
if(conn != null) {conn.close();}
} catch (Exception e) { }
}
}
}