JDBC - Create Table

GetEmp.java 파일 테스트가 성공했다면 이제부터 본격적인 JDBC 프로그래밍 예제를 실습하자.
준비한 예제는 명함관리 프로그램이다.
이번 장에서는 관련 테이블과 시퀀스를 JDBC를 이용해서 생성한다.

CREATE TABLE NAMECARD (
    NO  NUMBER CONSTRAINT PK_NAMECARD PRIMARY KEY,  -- 고유번호
    NAME    VARCHAR2(20) NOT NULL,    -- 이름
    MOBILE  VARCHAR2(20) NOT NULL,    -- 손전화
    EMAIL   VARCHAR2(40),   -- 이메일
    COMPANY VARCHAR2(60)    -- 회사
);
 
CREATE SEQUENCE SEQ_NAMECARD_NO
INCREMENT BY 1
START WITH 1;

JDBC 프로그래밍 순서를 다시 한번 기억해 보자.

  1. JDBC 드라이버 로딩
  2. Connection 맺기
  3. SQL 실행
  4. [SQL문이 select문이었다면 ResultSet을 이용한 처리]
  5. 자원 반환

Package Explorer 뷰에서 jdbc 프로젝트에 패키지는 net.java_school.jdbc.test로 하여 NamecardDDL.java 를 만든다. 모든 코드는 메인 메소드에 구현하도록 하겠다.

1. JDBC 드라이버 로딩

Class.forName() 메소드를 이용해서 오라클 JDBC 드라이버의 시작 클래스를 메모리에 로딩한다.
forName() 메소드의 아규먼트인 문자열 oracle.jdbc.driver.OracleDriver 는 GetEmp.java 에서 참고한다.
JDBC 드라이버 로딩
Class 클래스의 forName() 메소드는 ClassNotFoundException 을 핸들링 해주어야 하는 메소드이기 때문에 위와 같이 컴파일 에러가 보인다.
이클립스의 코드 어시스트 도움을 받아서 (도움을 받을려면 마우스로 컴파일 에러가 발생하는 코드에 위치시키면 된다) 그림과 같이 두번째 해결책을 선택하여 try ~ catch 문이 삽입되도록 한다.
JDBC 드라이버 로딩 ClassNotFoundException 익셉션 핸들링

2. Connection 맺기

커넥션은 DriverManager 클래스의 getConnection(,,) 메소드를 이용한다.
커넥션 맺기
Connection 과 DriverManager 는 JDBC 관련 인터페이스와 클래스로 java.sql 패키지에 있다.
위 그림과 같은 컴파일 에러는 코드 어시스트에서 첫번째 해결책을 선택하여 import 문장을 추가하도록 한다.
커넥션 맺기 import java.sql.*; 추가
DriverManager.getConnection(,,) 메소드의 첫번째 아규먼트는 url 값이다.
이 값 역시 GetEmp.java 소스를 참고한다.
두번째 아규먼트는 사용자 계정이고 세번째 아규먼트는 계정 비밀번호이다.
scott 계정에 테이블과 시퀀스를 만들기로 했으므로 두번째와 세번째 아규먼트는 각각 scott과 tiger이다.
커넥션 맺기 DriverManager.getConnection(String,String,String) 메소드 완성
DriverManager.getConnection(,,) 메소드는 SQLException 익셉션을 핸들링 해주어야 한다.
위 그림처럼 코드 어시스트의 두번째 해결책을 선택해서 try ~ catch 문으로 익셉션을 핸들링 하도록 한다.
커넥션 맺기 SQLException 익셉션 핸들링
이후부터 나오는 메소드는 SQLException 익셉션을 핸들링 해주어야 하므로 이후부터는 코드는 try 블록에 구현한다.
그리고 Connection 타입의 con 변수 선언은 try 블록 밖에 두어야 한다.
왜냐하면 finally 블록에서 con.close(); 코드로 자원 반납 할 때 finally 블록도 con이 해석될 수 있는 영역이어야 하기 때문이다.
커넥션 맺기 con 변수 선언을 try 블록밖으로

3. Statement 얻기

Statement 타입의 stmt 변수 선언 역시 나중에 자원 반납을 위한 코드구현을 고려해서 try 블록 밖에 둔다.
Statement 가 해석되지 않는 타입이라는 컴파일 에러를 만나면 코드 어시스트 도움을 받아
import java.sql.Statement; 문이 삽입되도록 한다.
Statement 얻기, stmt 변수 선언을 try 블록밖으로, import java.sql.Statement; 추가

4. SQL 실행

다음은 SQL문을 실행하는 단계이다.
먼저 실행시킬 SQL문을 문자열로 만든다.
아래 코드처럼 --로 시작하는 SQL 주석을 지운 SQL문으로 자바 문자열를 만든다.

Connection con = null;
Statement stmt = null;
String sql = null;
try {
	// Connection 맺기
	con = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:XE", "scott", "tiger");
	// Statement 얻기
	stmt = con.createStatement();
	sql = "CREATE TABLE NAMECARD ( " +
		"NO  NUMBER CONSTRAINT PK_NAMECARD PRIMARY KEY, " +
		"NAME    VARCHAR2(20) NOT NULL, " +
		"MOBILE  VARCHAR2(20) NOT NULL, " +
		"EMAIL   VARCHAR2(40), " +
		"COMPANY VARCHAR2(60))";
	stmt.executeUpdate(sql);
	
} catch (SQLException e) {
	// TODO Auto-generated catch block
	e.printStackTrace();
}

Statement의 executeUpdate() 호출할 때 테이블을 생성하는 자바 문자열을 아규먼트로 전달해 SQL문을 실행한다.
이어서 시퀀스를 생성하는 SQL문을 자바 문자열로 만든다.
Statement의 executeUpdate() 호출할 때 시퀀스를 생성하는 자바 문자열을 아규먼트로 전달해 SQL문을 실행한다.

Connection con = null;
Statement stmt = null;
String sql = null;
try {
	// Connection 맺기
	con = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:XE", "scott", "tiger");
	// Statement 얻기
	stmt = con.createStatement();
	sql = "CREATE TABLE NAMECARD ( " +
		"NO  NUMBER CONSTRAINT PK_NAMECARD PRIMARY KEY, " +
		"NAME    VARCHAR2(20) NOT NULL, " +
		"MOBILE  VARCHAR2(20) NOT NULL, " +
		"EMAIL   VARCHAR2(40), " +
		"COMPANY VARCHAR2(60))";
	stmt.executeUpdate(sql);
	sql = "CREATE SEQUENCE SEQ_NAMECARD_NO " +
		"INCREMENT BY 1 " +
		"START WITH 1";
	stmt.executeUpdate(sql);
} catch (SQLException e) {
	// TODO Auto-generated catch block
	e.printStackTrace();
}

5. 자원 반납

finally 블록을 만들고 finally 블록안에 자원 반납 코드를 삽입한다.
생성되는 순서의 역순으로 자원을 반납해야 하므로 stmt.close(); 가 먼저 나와야 한다.
자원 반납 코드 SQLException 관련 컴파일 에러
Statement의 close() 메소드는 SQLException 익셉션을 핸들링 해주어야 하는 메소드이므로 위처럼 처럼 컴파일 에러가 발생한다.
이때는 코드 어시스트 도움을 받아서 try ~ catch 블록이 삽입되도록 한다.
Connection의 close() 메소드도 마찬가지로 SQLException 익셉션을 핸들링 해주어야 하는 메소드이므로 con.close(); 역시 try ~ catch 블록안에 위치하도록 코드 어시스트의 도움을 받는다.
자원 반납 코드 완성
자원반납은 JDBC 코드에서 가장 중요하다. 꼭 잊지 말고 빠지지 않게 해야 한다.
NamecardDDL.java 를 실행한다.
익셉션이 발생하지 않으면
SQL*PLUS 로 scott 계정에 접속하여 테이블과 시퀀스가 생성되었는지 확인한다.
익셉션이 발생한다면 catch블록에 SQL문을 출력해본다.
JDBC의 단점 중 하나는 SQL 문을 자바 문자열로 바꿔야 한다는 데 있다.
SQL문을 자바문자열로 바꾸는 과정에서 띄어쓰기가 잘못되는 실수가 많이 나온다.

C:\ Command Prompt
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\Documents and Settings\kim>sqlplus scott/tiger

SQL*Plus: Release 10.2.0.1.0 - Production on 토 1월 8 21:11:20 2011

Copyright (c) 1982, 2005, Oracle.  All rights reserved.


다음에 접속됨:
Oracle Database 10g Release 10.2.0.1.0 - Production

SQL> select tname from tab;

TNAME
------------------------------------------------------------
DEPT
EMP
BONUS
SALGRADE
NAMECARD

5 개의 행이 선택되었습니다.

SQL> select sequence_name from user_sequences;

SEQUENCE_NAME
------------------------------------------------------------
SEQ_NAMECARD_NO

SQL>

NamecardDDL.java 를 다시 실행하면 익셉션이 발생한다.
똑같은 이름의 테이블과 시퀀스가 이미 scott 계정에 존재하기 때문이다.
JDBC로 테이블과 시퀀스를 생성하는 예제를 해보았다.
하지만 이와같이 JDBC를 이용한 DDL 문장을 실행하는 경우는 드물다.

executeUpdate
Statement의 executeUpdate() 메소드는 create table.. 과 같은 DDL문이나 DML문(INSERT, UPDATE, DELETE)을 실행할 때 사용한다.