21-JDBC



JDBC

sql는 데이터 접근을 가능하게 하는 기능 언어일 뿐이다. 예를 들어 회원가입을 해야한다면, db에 저장하고 create tabl/ insert 키보드 입력해야 한다면, sql만으로는 불가능하고 자바언어에서 db 이용이 가능하게 하는 라이브러리 모음이 필요하다. 그것이 JDBC(Java Database Connectivity)

  • 자바언어의 특성상 소스코드를 한 번 작성하면 동일하게 실행되고, 따라서 jdbc소스를 한 번 작성하면 모든 db이용이 가능하다. 즉 db독립적 형태 유지가 가능하다.



DB 연결

자바 프로그램 내에는 다음과 같은 인터페이스가 내장되어 있어, sql db연결이 가능하다.

  • DB종류마다 (표준SQL 독자적SQL 데이터 타입 등) 다르며, 데이터베이스마다 연결하는 방법 또한 다 다르다.

  • database에서 commit을 하지 않을 시 jdbc는 대기 중, 실행되지 않는다. jdbc는 자동 commit

api - java.sql.*  (java.sql.인터페이스)

 	interface Connection { 

		void connect(); 

	}  
class OracleConnection implements Connection{

public void connect(){ oracle db 연결 라이브러리 호출 }

}


eclipse - SQL 연결

  • oracle의 objbc6.jar(버전에 따라 다름)를 사용 jdk 경로 jre/lib/ext 안에 이동시킨다. 그리고 이클립스를 재시작.
    • 여러개의 자바 클래스 파일들이 모여있는 라이브러리 소프트웨어 패키지 파일 포맷인 JAR(Java Archive)를 사용함으로써, SQL과 관련된 명령어로 데이터 송출 및 조회가 가능해진다.



JAVA eclipse 내에서 DB를 연동

순서: 1. Connection -> 2. Statement -> 3. Result or Update -> 4. Close


  1. JDBC driver (자바클래스) 등록 메모리 로드

    Class.forName ( "oracle.jdbc.driver.OracleDriver");
    
    • oracle.jdbc.driver.OracleDriver: objbc6.jar 내부에 포함되어 있는 메소드 이름
  2. db 연결

    db 독립적 통일 호출

    Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:xe", "hr", "hr")
    
    • @127.0.0.1:1521 는 서버 ip를 의미한다. 127.0.0.1:1521(=localhost)은 어느 컴퓨터도 상관 없이 자신의 컴퓨터를 가르킨다. 내 컴퓨터 내부의 SQL을 사용하겠다는 것.
      • 후에 한 대의 db를 사용해서 공유한다면, db가 설치되어있는 ip로 지정하면 됨.
    • xe 는 버전을 의미(정해져있음)
    • “hr”, “hr” = “계정 이름”,”계정 비밀번호” : 해당 계정에 접속한다.
  3. SQL전송

    SQL 전송시, createStatement, preparedStatement 두 가지 객체를 사용할 수 있다.

    Interface인 Statement는 SQL을 전송하는 역할을 한다.

    • createStatement와 preparedStatement

      PreparedStatement는 Statement를 상속받는 형태를 갖고 있다. 
           
      		interface PreparedStatement extends Statement{
           
      		executeQuery(); // 공통
           
      		executeUpdate(); // 공통
           
      		setInt/setDouble/setString/setDate 등이 Prepared에 추가되어 있음. 
           
      					}
      


    1) createStatement

    • insert
      • insert delete update 실행 시 Statement 인터페이스에서 executeUpdate(String sql) 을 사용
    Statement st = con.createStatement(); //Connection 내의 createStatement 메소드 사용
    //실행
    st.executeUpdate("insert|update|delete")
    
    String sql = "insert into c_emp values(" + args[0] + ", "
    				+ "'" + args[1] + "','" + args[2] +"', " + args[3] + ", " + args[4] + ")";
    // : update 실행 시, 변수 결합방식은 +를 사용한다. 
       
    Statement st = con.createStatement();
    int cnt = st.executeUpdate(sql);
    //excuteUpdate는 행의 개수(int)를 반환한다. 
    
    • select
      • select 실행 시 Statement 인터페이스에서 executeQuery 사용, executeQuery의 리턴타입은 ResultSet
      • ResultSet : 최초 리턴되었을 때 커서가 가리키는 곳은 첫 번째 데이터가 아닌 MetaData 영역이다.
    String sql = "select*from c_emp";
    //sql을 저장, 전송, 결과를 저장 (그릇에 담기)
    Statement st = conn.createStatement();
    //실행(담은 것을 꺼내서 실행)
    ResultSet rs = st.executeQuery(sql);
    


    2) PreparedStatement

    • insert

      • Prepared에는 변수를 지정할 필요가 없고, 물음표(?)를 값으로 지정 후 이후 변수값을 지정한다.

        String sql = "insert into c_emp values(?, ?, ?, ?, ?)";
        PreparedStatement st = conn.prepareStatement(sql);
               
        st.setInt(1, 800);
        st.setString(2, "Emma");
        st.setString(3, "Employee"); 
        st.setDouble(4, 1000.0);
        st.setInt(5, 10);
        
    • select

      String sql = "select r, first_name, salary from (select row_number() over(order by salary desc) as r, salary, first_name from employees) where r between ? and ?"; 
           		
      		st = conn.prepareStatement(sql);
           		
      		st.setInt(1, Integer.parseInt(args[0]));
      		st.setInt(2, Integer.parseInt(args[1]));
           
      		rs  = st.executeQuery();//executeQuery는 결과(result)를 return.
      


  4. sql 결과 검색


  1. db 연결 해제

    tcp 소켓, 파일도 close. db도 반드시 close 처리한다.

    ResultSet rs = null;
    PreparedStatement st = null;
    Connection conn = null;
    		try{
          conn = DriverManager.getConnection
          rs  = st.executeQuery();  
          st = conn.prepareStatement(sql);
        }catch(){
             
        }finally{
          rs.close();
    			st.close();
    			conn.close();
        }
    //순서 주의: ResultSet > Statement > Connection 순서로 close();
    



다음은 위의 절차로 oracle 의 hr 계정에 연동하고 생성/조회하는 과정이다.

insert

package jdbc;

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

public class PreparedInstertTest {

	public static void main(String[] args) {
	
		Connection conn = null;
		try {
		
		Class.forName("oracle.jdbc.driver.OracleDriver");//메모리 로드

		conn = DriverManager.getConnection
				("jdbc:oracle:thin:@127.0.0.1:1521:xe", "jdbc", "jdbc");//DB호출
		System.out.println("db연결성공");

		String sql = "insert into c_emp values(?, ?, ?, ?, ?)"; 
    /*값은 나중에 넣어도 되니 형식만 맞추고 변수값은 ?로 제시. 
		실행 sql 형태를 잡은 상태, 문법 검사 마치고 준비상태 */
      
		PreparedStatement st = conn.prepareStatement(sql);
		//? 부분값 세팅 = sql  문장 입력 파라미터값 세팅 
		st.setInt(1, 800); //1번 ? 변수값 800 입력. oracle에서는 자동 number변경
		st.setString(2, "Emma"); //2번 ? 변수값 "Emma"입력. oracle에서는 varchar2로 자동 변경, "" > ''로 변경 (Statement가 변경해줌)
		st.setString(3, "Employee"); 
		st.setDouble(4, 1000.0);
		st.setInt(5, 10);
		
		//실행 
		int insertrow = st.executeUpdate(); 
    //이미 검사 마치고 준비상태, sql을 변수값으로 넣으면 다시 ?, ?, ? .. 로 초기화된다. 변수값 x
      
		//리턴결과 검색 
		System.out.println(insertrow + " 개의 행 삽입");
		
		
		
		System.out.println("db연결해제성공");
		}catch(ClassNotFoundException e) {
			System.out.println("드라이버 세팅 확인");
		}catch(SQLException e) {
			System.out.println("DB연결 정보 확인");
			e.printStackTrace();
		}finally {
			try {
			conn.close();
			}catch(SQLException e) {  } 
		}
		
	}

}


select

package jdbc;

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

public class PreparedSelectTest2 {

	public static void main(String[] args) {
		Connection conn = null;
	    PreparedStatement st = null;
		ResultSet rs = null;
	
		try {

		Class.forName("oracle.jdbc.driver.OracleDriver");

		conn = DriverManager.getConnection
				("jdbc:oracle:thin:@127.0.0.1:1521:xe", "hr", "hr");
		System.out.println("db연결성공");

		
		String sql = "select r, first_name, salary from (select row_number() over(order by salary desc) as r, salary, first_name from employees) where r between ? and ?"; 
		
		//sql 저장-전송-결과저장 (그릇담기) 
		st = conn.prepareStatement(sql);
		
		//입력 파라미터값 세팅
		st.setInt(1, Integer.parseInt(args[0]));
		st.setInt(2, Integer.parseInt(args[1]));
		
		//실행 
		rs  = st.executeQuery();
		
		//리턴결과 검색 
		while(rs.next()) {
			int r = rs.getInt("r");
			String emp_name = rs.getString("first_name");
			double salary = rs.getDouble("salary");
			System.out.println( r + "|" + emp_name + "|"  + salary  );
		}
		
		
		
		System.out.println("db연결해제성공");
		}catch(ClassNotFoundException e) {
			System.out.println("드라이버 세팅 확인");
		}catch(SQLException e) {
			System.out.println("DB연결 정보 확인");
			e.printStackTrace(); // 자세한 원인 출력 
		}finally {
			try {
				//순서 주의 
			rs.close();
			st.close();
			conn.close();
			
			}catch(SQLException e) {  } 
		}
		
	}

	
}

그러나 JDBC에서 DDL 실행하는 것은 권고되는 방법이 아니다. 이것은 반드시 db 내부에서 할 수 있도록. 즉, sql 툴 내에서 사용하라. : 사용은 가능하나, 여러개의 jdbc 프로그램이 하나의 table을 작업하면, 충돌이 발생. 보안적으로 좋지 않다.



부가설명

id(int) name(char) salary(double)
100 이자바 5000.0
     

rs.next() - true/false : 다음 행에 데이터가 있으면 true, 없으면, false를 return

  • 행을 읽어올 때 아래와 같은 구문을 사용한다.

while(rs.next()){  // 다음 행이 존재하는만큼 읽어온다. 

rs.getInt(1);  // ==  rs.getInt("id")

rs.getString(2) // == rs.getString("name")

rs.getDouble(3) // == rs.getDouble("salary")

}


Data type JAVA ORACLE
정수 : rs.getInt() int number(n)
실수 : rs.getDouble() double number(n, s)
문자 : rs.getString() String char, varchar2(n);
날짜 : rs.getDate() java.sql.Date date
rs.getString() String to_char(sysdate, ‘yy/mm/dd’)
> 문자형 결과


DDL (ceate) jdbc - 자동 commit run.. - 자동 commit
DCL (grant) jdbc - 자동 commit run.. - 자동 commit
DML jdbc - 자동 commit run.. - 수동 commit
commit or rollback
DQL = select