본문 바로가기
Spring

2022-11-11 JDBC 이론 정리

by HTT 2022. 11. 12.
JDBC(Java Database Connectivity)

 

=> java를 DBMS와 연동하기 위한 기술(java프로그램에서 SQL문을 실행하기 위해서 제공되는 API)


 

💡 오라클에 접속하여 JDBC를 사용하기 전에 해야할 일

 

1. 오라클 드라이버 다운받기
- 모든 DBMS의 제조사 홈페이지에서 다운로드


- 오라클이 설치되어 있는 경우(xe)
 C:\oraclexe\app\oracle\product\11.2.0\server\jdbc\lib\ojdbc6.jar을 사용
** ojdbc6.jar : 오라클 드라이버


2. JVM(자바를 실행하기 위한 가상 기계(컴퓨터))이 인식할 수 있는 위치로 오라클 드라이버를 복사
=> 코드를 실행하기 위해 JVM이 찾을 수 있는 위치에.


1) 작업프로젝트 선택
2) 프로젝트 선택 후 단축메뉴 - [Build path] - [Configure build path] 선택
3) 대화상자의 세 번째 탭인 [Libraries]탭 선택
4) [classPath] 선택 후 [Add External Jar..] 버튼을 선택 후 라이브러리 파일의 경로를 찾아 드라이버를 등록
    C:\oraclexe\app\oracle\product\11.2.0\server\jdbc\lib\ojdbc6.jar
   
   


💡 자바로 JDBC연동 - API로 작업

 

1. 오라클 드라이버 로딩


클래스로더를 이용해서 드라이버의 핵심 클래스를 메모리에 로딩
java.lang패키지의 Class라는 클래스의 forName이라는 메소드를 이용해서 오라클 드라이버의 핵심클래스를 메모리에 로딩
핵심클래스는 드라이버클래스라고 하며 드라이버클래스는 어떤 DBMS를 이용하냐에 따라서 달라진다.
   
[문법]
  class.forName("메모리에 로딩하고 싶은 클래스명(패키지까지 명시)")
   
[오라클]
  Class.forName("oracle.jdbc.driver.OracleDriver")  //oracle.jdbc.driver패키지의 OracleDriver.class 파일
** oracle.jdbc.driver.OracleDriver : 오라클 드라이브명(오라클 드라이버의 핵심클래스)
   


2. DB서버에 연결하기
=> java.sql패키지의 API를 이용
   
- DriverManeger의 getConnection메소드를 이용해서 DB서버에 연결


1) static메소드이므로 클래스 이름으로 엑세스


2) throws하고 있는 SQLException은 Exception클래스의 하위 클래스이르모 문법적으로 Exception처리를 해야 한다.


3) 매개변수

① url : 연결문자열(어떤 DBMS를 쓰느냐에 따라 내부에서 인식되어질 문자열을 다른 형식으로 지정 - 교재참고)
[오라클]
jdbc:oracle:thin:@ip:port:데이터베이스의 서비스 명   (나의 데이터 베이스 서비스명 : xe)
오라클에서 사용하는 프로토콜 : @DBMS가 설치되어 있는 서버의 ip와 접속port(1521) : 오라클 설치할 때 설정하는 값으로 express edition버전은 xe
   
ex) 127.0.0.1 or localhost => 현재 작업 중인 PC(로컬)
       jdbc:oracle:thin:@127.0.0.1:1521:xe
       jdbc:oracle:thin:@localhost:1521:xe
       jdbc:oracle:thin:@172.30.1.37:1521:xe
   
② user : 사용자계정(scott)
③ password : 패스워드(scott계정의 패스워드:tiger1234)


4) 리턴타입
java.sql.Connection을 리턴
DriverManager클래스의 getConnection메소드는 DB서버에 연결하고 연결정보를 객체로 만들어서 리턴
                                                              ---------
                                                                 java.sql.Connection
표준 API는 java.sql.Connection을 리턴한다고 명시되어 있지만 DBMS의 드라이버가 어떤 드라이버가 로딩되어 있는지에 따라 달라진다.
Connection은 인터페이스
  


3. SQL문 실행 기능이 제공되는 객체를 생성


[상속구조]
      +---------------+
      |  Statement       |               - 정적SQL을 실행할 때 사용(보안취약)
      +---------------+
             ^   
             |
   +-------------------------+
   | PreparedStatement       |       - 동적SQL을 실행할 때 사용(보안취약)
   +-------------------------+
             ^   
             |
   +------------------------+
   | CallableStatement       |          - 각 DBMS에 특화된 SQL로 작성된 명령문을 실행
   +------------------------+         오라클 : PL-SQL
   
=> SQL문을 실행하기 위한 메소드를 갖고 있는 클래스


   
1) Statement객체를 이용
Connection객체가 갖고 있는 createStatement메소드를 이용해서 생성
[형식]
Statement stmt = con.createStatement()
: stmt객체는 어떤 DBMS의 드라이버가 로딩되어 있냐에 따라 달라진다.
      
2) PreparedStatement객체를 이용
Connection객체에 정의되어 있는 preparedStatement메소드를 이용해서 생성
캐시사용
① 쿼리 문자 분석
② 컴파일
③ 실행
Statement는 SQL을 실행하는 과정에서 매번 반복해서 위에 3가지 내용을 처리하고 있지만 PreparedStatement는 한 번만 작업하고 캐시에서 꺼내서 사용한다.
PreparedStatement객체가 SQL문을 실행하는 방식은 미리 SQL문을 파싱해 놓고 외부에서 입력받는 값을 전달해서 실행할 수 있도록 하는 방식


   ⓐ sql문을 전달하며 PreparedStatement객체를 생성
   => sql문을 미리 파싱하는 방법이므로 Connection객체의 preparedStatement메소드를 이용해서 PreparedStatement객체를 만들 때 sql문을 전달해야 한다.
        PreparedStatement ptmt = con.preparedStatement(sql);
      
   ⓑ sql문을 작성할 때도 외부에서 입력 받아 처리할 부분은 ?로 대체하여 표시한 후 작업한다.
   String sql = "insert into customer values(?,?,?,?,sysdate,1000,?);
   => ?는 값의 자리만 처리할 수 있다(컬럼명에 ?는 처리할 수 없다).
       
   ⓒ ?에 대한 값을 셋팅
   ?는 외부에서 전달받은 값을 설정해 주어야 SQL문이 완성된다.
   setXXX메소드는 타입과 연결해서 알맞은 setter메소드를 선택해서 작업(ResultSet의 getter메소드와 타입매칭은 동일)
   ptmt.setString(1, "jang") => 첫 번째 물음표 자리에 "jang"을 셋팅
                                 ---
                       ?가 정의된 순서
   ptmt.setInt(2, 1000) => 두 번째 물음표 자리에 1000을 지정
       
       
4. SQL문 실행하기
1) Statement를 사용
① executeUpdate : insert, delete, update 명령문을 실행
매개변수에 전달된 sql문이 실행됨
실행결과로 몇 개의 row가 반영되었는지 리턴
int result = stmt.executeUpdate(sql)
   ----------
     ㄴ> 몇 개의 행이 삽입, 수정, 삭제되었는지 리턴
                     
② executeQuery : select명령문을 실행
실행한 후 조회된 테이블을 리턴, DBMS에서 조회된 테이블을 자바에서 사용하기 위해서 만들어놓은 객체가 ResultSet이다.
실제로는 어떤 DBMS가 사용되었는지에 따라서 다른 ResultSet객체(ResultSet의 하위)가 리턴
                    
2) PreparedStatement를 사용
① executeUpdate     ② executeQuery
Statement메소드와 동일하게 동작하지만 PreparedStatement 매개변수가 없다.
      
   
5. 결과처리
1) insert, delete, update
- 모두 int를 리턴하므로 동일한 방법으로 처리
  int result = stmt.executeUpdate(sql)  
        
2) select
sql-plus프로그램을 이용해서 select sql문을 실행할 때 결과로 보여지는 2차원 표의 데이터를 자바에서 사용할 수 있도록 만들어 놓은 객체가 ResultSet이다.
      
- select문을 실행하면 ResultSet을 리턴하므로 ResultSet타입의 변수를 선언해서 결과를 참조
  ResultSet rs = stmt.ececuteQuery(sql문)
  ResultSet rs = ptmt.executeQuery()  <- PreparedStatement는 변수X
        
- ResultSet에 있는 테이블의 데이터를 읽기 위해 ResultSet이 제공하는 메소드를 이용해서 작업
  Cursor를 다음 레코드로 이동하면서 레코드 갯수만큼 반복작업을 수행
  ResultSet객체의 next()메소드를 이용하여 다음레코드로 커서를 이동. next()는 커서를 이동했을 때 레코드가 존재하면        true를 리턴하고 없으면 false를 리턴
       
        while(rs.nest()) {  ---> true/false를 리턴하므로 반복문 중 while문을 이용하여 작업
            // 레코드의 각 컬럼을 읽는다.
   
        }   
   
- 한 번에 하나의 컬럼만 읽을 수 있다.

ResultSet객체의 getXXX메소드를 이용하여 컬럼값을 읽는다. 타입에 따라 다른 메소드를 이용
        
* 오라클타입이 varchar2나 char인 경우 : java의 String
   getString(컬럼명) or getString(컬럼순서 index)    // rs.getString("id")+"\t"  or  rs.getString(1)
                                                                --------------
                                                  원본 테이블에 정의된 컬럼의 순서가 아니라
                                                  조회된 테이블에 포함된 컬럼의 순서
                                     
* 오라클 타입이 number : java의 int
   getInt(컬럼명) or getInt(컬럼순서 index)
        
* 오라클 타입이 date : java의 Date
   getDate(컬럼명) or getDate(컬럼순서 index)
   
   while(rs.next()) {  -> 커서를 하나씩 다음레코드로 이동해라
          //  조회된 레코드 갯수만큼 반복해서 작업
    
   sysout(rs.getString("name")) -> name이라는 컬럼명으로 정의된 컬럼을 조회
   sysout(rs.getString(3)) -> 조회된 테이블의 3번째 컬럼을 조회
 
   }
   
 
6. 자원반납
- 클라이언트가 점유해서 사용하던 자원을 반납해야 한다.
- Connection, Statement, ResulrtSet까지 모든 자원을 반납
- close메소드를 이용해서 처리
- 만들어진 순서가 아니라 제일 마지막에 생서된 객체부터 반납한다.

댓글