DataBase

221205 오라클 : java와 오라클 연동(JDBC)

헤니s 2022. 12. 5. 20:41

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) { }
		}
	}
}