JDBC를 이용한 DB 처리

순서

1. JDBC드라이버 로딩

  • JDBC 드라이버는 DB를 만든 회사에서 제공한다.
  • Class.forName("oracle.jdbc.driver.OracleDriver");

2. 해당 DB에 접속

  • 접속이 성공하면 Connection객체가 생성된다.
  • DriverManager.getConnection()메서드를 이용한다. (static메서드)

3. 질의 (SQL명령 수행)

  • Statement객체 또는 PreparedStatement객체를 이용하여 SQL문장을 실행한다.
  • Connection객체로부터 Statement객체를 제공받을 수 있다 (순서를 잘 지켜야함)

4. 질의 결과를 받아서 처리

  • 1) SQL문이 SELECT 일 경우
    • executeQuery()
    • ResultSet객체가 만들어지고, 거기에 SELECT한 결과가 저장된다.
  • 2) SQL문이 INSERT, UPDATE, DELETE 일 경우
    • executeUpdate()
    • 정수값을 반환한다. (보통 실행에 성공한 레코드 수를 의미)

5. 종료 (자원반납)

  • 사용했던 자원을 모두 반납한다 -> 자원 반납을 하지 않으면 메모리 누수 발생!
if(rs != null) try {rs.close();} catch (SQLException e) {}
if(stmt != null) try {stmt.close();} catch (SQLException e) {}
if(conn != null) try {conn.close();} catch (SQLException e) {}

예시: T01_JdbcTest.java

  • main()에서 실행
Connection conn = null;
Statement stmt = null;
ResultSet rs = null; // 쿼리문이 select일 경우에 사용됨.

try {
  // 2-1. 드라이버 로딩(옵션)
  Class.forName("oracle.jdbc.driver.OracleDriver");

  // 2-2. DB접속 (Connection객체 생성)
  String url ="jdbc:oracle:thin:@localhost:1521/xe";
  String user = "LKR94";
  String password = "java";
  conn = DriverManager.getConnection(url, user, password);

  // 2-3. Statement 객체 생성 => Connection 객체를 이용한다
  stmt = conn.createStatement();

  // 2-4. SQL문을 Statement객체를 이용하여 실행하고 실행결과를 ResultSet에 저장함.
  String sql = "SELECT * FROM LPROD";
  rs = stmt.executeQuery(sql);

  /*
   * SQL문이...
   * 1) 		 SELECT		   => executeQuery()
   * 2) INSERT/UPDATE/DELETE => executeUpdate()
   */

  // 2-5. ResultSet 객체에 저장되어 있는 자료를 반복문과 next()메서드를 이용하여 차례로 읽어와 처리한다.
  System.out.println("실행한 쿼리문 : " + sql);
  System.out.println("=== 쿼리문 실행 결과 ===");
  // rs.next() => ResultSet객체의 데이터를 가리키는 포인터를 다음 레코드로 이동시키고 그 곳에 자료가 있으면 true, 없으면 false
  while(rs.next()) {
    // 컬럼의 자료를 가져오는 방법
    // 방법1) rs.get자료형이름("컬럼명")
    // 방법2) rs.get자료형이름("컬럼번호") => 컬럼번호는 1부터 시작
    System.out.println("LPROD_ID : " + rs.getInt("LPROD_ID"));
    System.out.println("LPROD_GU : " + rs.getString("LPROD_GU"));
    System.out.println("LPROD_NM : " + rs.getString("LPROD_NM"));
    System.out.println("------------------");
  }
  System.out.println("출력 끝...");
} catch (SQLException e) {
  e.printStackTrace();
} catch (ClassNotFoundException e) {
  e.printStackTrace();
} finally {
  // 6. 종료 (사용했던 자원을 모두 반납한다 -> 자원 반납을 하지 않으면 메모리 누수 발생!)
  if(rs != null) try {rs.close();} catch (SQLException e) {}
  if(stmt != null) try {stmt.close();} catch (SQLException e) {}
  if(conn != null) try {conn.close();} catch (SQLException e) {}
}

PreparedStatement + '?' 와일드카드

  • parsing 안하니 속도빨라짐
  • SQL Injection 일어날 걱정 x
    • SQL Injection: 사용자의 입력값에 의해 SQL문이 삽입되어 데이터베이스 서버를 조작할 수 있는 공격기법
  • ?의 위치는 1부터 시작 (인덱스처럼 0부터 아님)
  • setStirng 하면 '' 알아서 넣어줌, setInt는 안해줌

T02_MemberInfoTest.java

String sql = "INSERT INTO MYMEMBER "
		  + " (MEM_ID, MEM_NAME, MEM_TEL, MEM_ADDR) "
		  + " VALUES (?, ?, ?, ?) ";

pstmt = conn.prepareStatement(sql);
pstmt.setString(1, memId);
pstmt.setString(2, memName);
pstmt.setString(3, memTel);
pstmt.setString(4, memAddr);

Properties

예제

준비: 새 소스폴더에 res 만들어주기

  • 소스폴더: 컴파일대상이됨
    • project: build automatically 체크가 되어있기때문에 소스들이 자동으로 컴파일되고 있던 것
    • java build path: source에 이제 res도 추가됨
    • default output folder: res, src의 컴파일된 파일들을 bin에 담아주겠다

1단계: db.properties 생성

  • 대입연산자 기준 왼쪽: key & 오른쪽: value

2단계: 외부 properties 파일 읽어와 properties 객체로 처리하기

  • T03_PropertiesTest.java
  • main에서 실행
// 1. 읽어온 정보를 저장할 Properties객체 생성
Properties prop = new Properties();

// 2. 읽어올 파일명을 이용한 File객체 생성
File file = new FIle("res/db.properties"); // (= ./res/db.properties)

try{
  // 3. 파일 읽기를 수행할 FileInputStream객체 생성
  FileInputStream fis = new FileInputStream(file);

  // 4. Properties객체로 파일 내용 읽기
  // 파일 내용을 읽어와 key와 value값으로 분류한 후 properties객체에 저장
  prop.load(fis);

  // 5. 읽어온 자료를 출력하기
  // key 값만 읽어와 Enumeration 객체로 변환
  // Enumeration : iterator랑 비슷
  Enumeration<String> keys = (Enumeration<String>) prop.propertyNames();

  // key값 개수만큼 반복해서 값 출력하기
  // keys.hasMoreElements() : 다음 포인터 위치에 자료가 있으면 true, 없으면 false반환
  while(keys.hasMoreElements()) {
    String key = keys.nextElement();
    String value = prop.getProperty(key); // 중요! key 값만 알면 value 획득 가능

    System.out.println(key + " => " + value);
  }
  System.out.println("출력 끝...");
} catch (IOException e) {
  e.printStackTrace;
}

결과

ResourceBundle

  • ResourceBundle객체란?
    • 확장자가 properties인 파일 정보를 읽어와 key값과 value값을 분리한 정보를 갖는 객체
    • 읽어올 파일은 'key값=value값' 형태로 되어 있어야 한다
  • 객체 생성 후 파일을 지정할 때는 '파일명'만 지정하고 확장자는 지정하지 않는다
    • 확장자는 항상 properties이기때문에

Locale?

  • The java.util.Locale class object represents a specific geographical, political, or cultural region.
  • 지역의 언어, 나라 등의 정보를 가지고 있는 클래스

예제 T04

준비: 언어별 db.properties파일 생성

기본 db.properties

한국어 db_ko.properties

영어 db_en.properties

1단계: ResourceBundle 객체 생성

System.out.println(Locale.getDefault()); // ko_KR

// 1. Locale이 default일 때 (= 매개변수 없을 때)
ResourceBundle bundle = ResourceBundle.getBundle("db");

// 2. Locale을 미국으로 설정했을 때
ResourceBundle bundle = ResourceBundle.getBundle("db", Locale.US);

2단계: ResourceBundle 객체 안의 내용 출력

// key값들만 읽어오기
Enumeration<String> keys = bundle.getKeys();

// key값 개수만큼 반복해서 value값 가져오기
while (keys.hasMoreElements()) {
  String key = keys.nextElement();

  // key값을 이용하여 value값을 읽어오는 방법
  // => bundle객체변수.getString(key값);
  String value = bundle.getString(key);

  System.out.println(key + " => " + value);
}
System.out.println("출력 끝...");

결과

Locale이 default일 때 (매개변수 없을 때)

Locale 미국

그냥 db.properties는 이제 아무도 안읽어주네..^_ㅠ

properties 파일 이용한 DB 정보 설정

  • DB설정파일을 외부파일(.propeties)로 둠으로써 유지보수를 간편히
  • IT IS ALL ABOUT 유지보수!!!

방법1. Properties 객체 이용

  • P07_JDBCTest - JDBCUtil2.java 참고

핵심

  • 드라이버 로딩 이전에 properties객체를 생성 후 파일을 읽어들여 사용자가 직접 드라이버 주소, url, id, pw를 입력하는 것이 아닌 파일에 담겨있는 정보를 불러와서 쓴다는 것

비교

  • 자원반납 생략

db.properties 이용하지않을 때

db.properties 파일을 이용할 때

방법2. ResourceBundle 객체 이용

  • P07_JDBCTest - JDBCUtil3.java, T04_ResourceBundleTest 참고

핵심

  • FileInputStream 이용해서 파일 읽을 필요 없이, 객체 생성시 db.properties의 key와 value값이 나누어 저장이 되기때문에 훨씬 간결하다.
profile
갈 길이 멀다

0개의 댓글