본문 바로가기

Development/Java

[Java기초] 02.JDBC사용하기(Statement와 PreparedStatement 차이점)

무단 도용을 금합니다. (꼭 출저를 써주시길 부탁드립니다.)

개발 환경

  • Java : jdk-1.7.0-xx
  • 툴 : Eclipse kepler EE
  • DBMS : MySQL Community Server 5.6


JDBC연결에 관련된 글은 아래 링크를 참고해주세요.

[Java기초] 01.JDBC연결하기


전에 JDBC 연결에 이어 이번엔 기본적인 아래의 4가지 요소에 대해서 알아보려고 합니다.

JDBC프로그램에 필요한 3가지 인터페이스

  1. Connection
  2. Statement (PreparedStatement)
  3. ResultSet


또 이번에 예제에 필요한 데이터베이스와 테이블의 구조는 간단하게 아래와 같습니다.

CREATE DATABASE dbtest;    --데이터베이스의 이름은 dbtest입니다.

CREATE TABLE test_table(      --dbtest에 만들 테이블의 이름은 test_table이라고 하겠습니다.

no int auto_increment ,
name varchar(10) not null,
temp int,

PRIMARY KEY(no)
);




Connection

맨 처음 알아볼 인터페이스는 java.sql패키지의 Connection 입니다.
간단하게 한마디로 설명하자면 자바와 DB를 연결하는 객체의 인터페이스입니다.

실제로는 Statement와 ResultSet를 얻으려면 필수적으로 있어야하는 객체이기도 합니다.

1.Connection 객체 초기화 하기

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

private Connection conn = null;

위와같은 객체를 생성했다고 가정하고 Connection 인터페이스의 비어있는 private 멤버 객체(이하 conn)를 만들었습니다.

이 conn이라는 객체에 인스턴스를 생성해주기위해서 해당 DBMS의 드라이버를 설정해 줘야합니다.


1.1 인스턴스 얻기

인스턴스를 얻기 위해서는 DriverManager의 getConnection()이라는 메서드를 이용해야합니다.
이 메서드는 데이터베이스에 연결하는 실질적인 메서드라고 보면 됩니다.

getConnection메서드는 다음 3가지를 파라메터로 받아야합니다.

  • url : DBMS데이터베이스 접속경로입니다. jdbc:로 시작되는 패턴을 가지고 있으며 형식은 DBMS마다 다릅니다.
  • user : DBMS를 접속할때 사용하는 유저 아이디입니다.
  • password : DBMS를 접속할때 사용하는 유저의 패스워드입니다.

public Connection getConnection() {

String url = "jdbc:mysql://localhost:3306/dbtest";    //dbtest라는 이름을 가진 DB의 url
String user = "root";    //DBMS 유저 아이디
String password = "1234";    //DBMS 유저 암호

try{
    Class.forName("com.mysql.jdbc.Driver");    //connector의 드라이버 클래스 로드
    conn = DriverManager.getConnection( url , user , password );    //JDBC연결 (이곳에서 conn의 인스턴스를 얻는다)
    return conn;
catch (ClassNotFoundException | SQLException e) {
    System.out.println(e.getMessage());
    return null;
}

}


이 소스에서 연결에 실패하여 예외가 발생했다면 두가지 원인으로 볼 수 있습니다.

  • ClassNotFoundException : Class.forName메서드가 매개변수인 드라이버를 찾지 못해 발생하는 예외입니다.
                                            이곳 참고하세요
  • SQLException : MySQL서비스가 실행되고있지 않거나 JDBC연결 정보가 잘못 입력 되어 예외가 발생한 것입니다.

연결에 성공하였으면 다음에 사용할 Statement에 대해 알아보겠습니다.


Statement와 PreparedStatement

JDBC를 공부하면서 때 한번쯤 겪는 의문이 아닐까 생각합니다.
둘 중 어떤것을 써야할까요?

일단 둘은 상속관계에 있습니다.
Statement와 PreparedStatement는 각각의 장단점이 있어서
구현할 기능에 따라 이 둘을 적절히 사용하는 것이 좋다고 생각합니다.

아래의 다이어그램에서 보면 PreparedStatement는 Statement를 상속받고 있습니다

출처 :http://www.falkhausen.de/en/diagram/html/java.sql.Statement.html

링크는 제가 자주 참고하는 독일의 한 자바 문서(?) 사이트입니다.


Statement와 PreparedStatement는 JDBC프로그램에서 아주 중요한 역할을 하고있는 인터페이스입니다.

SQL문장을 실행하고 결과를 반환하는 기능들을 캡슐화한 인터페이스로 프로그램 내에서 제일 빈번하게 쓰이는 객체입니다.


먼저 Statement를 살펴보도록 해요.


1.Statement 

Statement의 주요 메서드는 아래와 같습니다.

 메서드명(파라메터)

리턴타입 

기능 

  execute(String sql)

 boolean

 sql문을 실행하고 성공하면 false가 리턴됩니다.

  executeQuery(String sql)

ResultSet

 sql문을 실행하고 ResultSet 형식의 결과를 리턴합니다.

  executeUpdate(String sql)

int

 insert, update, delete문을 실행하고 영향을 받은 행의 갯수나 0을 반환합니다. 실패한 경우 에러가 발생됩니다.

  close()

void 

 Statement의 리소스를 반납합니다.


일단 장단점에 대하여 간단히 설명하자면 아래와 같습니다.

Statement의 장점 : 

  • 동적으로 SQL문을 만들수 있다.
  • SQL문을 직접적으로 작성하기 때문에 쉽게 분석할 수 있다.
Statement의 단점 :
  • sql문이 문자열로 작성되기 문자열과 같은 값을 넣기위해 작은따옴표(')등의 처리를 직접 처리해야한다.
  • 잘못 작성된 경우 런타임에만(실행중 일때만) 확인할 수 있다.
  • 작성된 SQL문을 재사용하기 어렵다.



Statement도 conn과 같이 클래스의 필드로 지정하고 사용하는게 편한것 같아요.

조금 전에 만든 Connection 아래에 같이 쓰도록 하겠습니다.

import java.sql.Connection;
import java.sql.Statement;

private Connection conn = null;
private Statement
stmt = null;

이제 conn과 같이  Statement 인터페이스의 비어있는 private 멤버 객체(이하 stmt)를 만들었습니다.


stmt의 인스턴스는 conn으로부터 createStatement()라는 메서드를 통해 생성합니다.


insert문을 실행하는 메서드를 만들어서 알아보도록 할께요.

public void insert(String name, int temp) {
String query = "insert into test_table (name,temp) values('"+name+"', "+temp+")";//쿼리문 작성
        conn = this.getConnection();    //위의 메서드로 conn을 초기화합니다.

  try{

stmt = conn.createStatement(); //Connection정보를 담은 객체 conn 으로부터 Statement 인스턴스를 생성한다.

System.out.println(stmt.executeUpdate(query));    //실행할 쿼리문을 동적으로 바꿀수 있는 구조
//성공이면 0 이상, 실패면 예외가 발생합니다.

stmt.close();
        //stmt는 이 메서드가 실행될때마다 생성되니까 메서드가 끝날때 자원을 반납하도록함.
        conn.close();        //더이상 필요하지 않다면 conn의 자원을 반납해야합니다.
  } catch(SQLException e) {
    System.err.println(e.getMessage());
  }

}

이 코드를 보면 대충 구조를 알 수 있습니다.

stmt는 실행 메서드(execute메서드)들을 통해 SQL문장을 실행합니다.


2.PreparedStatement

PreparedStatement는 기본적으로 Statement에서 더 추가된 기능을 사용할 수 있습니다.

위에서 본 stmt를 PreparedStatement로 알아볼께요.

PreparedStatement의 추가된 주요 메서드는 아래와 같습니다.

 메서드명(파라메터)

리턴타입 

기능 

  execute()

 boolean

 sql문을 실행하고 성공하면 false가 리턴됩니다.

  executeQuery()

ResultSet

 sql문을 실행하고 ResultSet 형식의 결과를 리턴합니다.

  executeUpdate()

int

 insert, update, delete문을 실행하고 영향을 받은 행의 갯수나 0을 반환합니다. 실패한 경우 에러가 발생됩니다.

  set<G>(int index, <G> value)

void 

 사전에 준비된 SQL문에 값을 대입합니다.

  close()

void

 PreparedStatement의 자원을 반납합니다. 

stmt와 차이점은 실행 메서드들의 매개변수를 넣지않는 점입니다.

그 이유는 아래에서 알아보도록 하겠구요.


보완된 점에 대해서 알아보면 아래와 같습니다.

PreparedStatement 보완된 장점 : 

  • sql문장을 미리 컴파일할 수 있도록 개선되었다.
  • 작은따옴표(')같은 문자열 등을 자동적으로 처리한다.
  • 재사용하기 편리하다.

stmt와 같은 예제를 통해 알아보도록 할께요.

import java.sql.Connection;
import java.sql.Statement;
import java.sql.PreparedStatement;

private Connection conn = null;
private Statement 
stmt = null;
private PreparedStatement pstmt = null;


PreparedStatement도 pstmt라고 칭하도록 하겠습니다.

pstmt의 인스턴스는 stmt와 조금 다르게 PrepareStatement(String sql)라는 메서드를 통해 생성합니다.


insert문을 실행하는 메서드를 다른 이름으로 만들겠습니다.

public void insertPrepare(String name, int temp) {
String query = "insert into test_table (name,temp) values( ? , ? )";//쿼리문 작성
        conn = this.getConnection();

  try{

pstmt = conn.prepareStatement(query);    //Connection정보를 담은 객체 conn 으로부터 PreparedStatement 인스턴스를 생성한다.
       
      pstmt.setString(1, name);
      
pstmt.setInt(2, temp);

System.out.println(pstmt.executeUpdate());    //실행할 쿼리문을 동적으로 바꿀수 있는 구조
//성공이면 0 이상, 실패면 예외가 발생합니다.

pstmt.close();
        //stmt는 이 메서드가 실행될때마다 생성되니까 메서드가 끝날때 자원을 반납하도록함.
        conn.close();        //더이상 필요하지 않다면 conn의 자원을 반납해야합니다.
  } catch(SQLException e) {
    System.err.println(e.getMessage());
  }

}

이 코드에서는 stmt와 pstmt의 차이점을 알아야합니다.

처음 conn.prepareStatement의 메서드에 ?이 포함된 SQL문을 파라메터로 넘긴 후
pstmt의 set[자료형]형식의 메서드로 값을 정해줍니다.

set[자료형]의 파라메터는 int형식의 순서번호와 들어가야 할 값을 파라메터로 받아 삽입됩니다.

javadoc(자바 도움말 문서)에 있는 setString메서드를 보면 아래와 같이 나와있는데,

void java.sql.PreparedStatement.setString(int parameterIndex, String x) throws SQLException

여기서 파라메터를 보면 parameterIndex와 x를 받습니다. 만약 setString(1, "heather");라고 보면
SQL문의 첫번째 물음표에 "heather"라는 문자열을 대입하는것입니다.

여기서 알아둬야 할 것은 물음표의 순서번호가 1부터 시작한다는 것작은따옴표와같은 문자열 처리를 하지 않아도 된다는 것입니다.



ResultSet

ResultSet은 결과가 있는 SQL문장을 실행한 후 결과를 받을 때에만 사용합니다.(따라서 결과값이 있는 select문 이외에는 잘 사용하지 않습니다.)

이 인터페이스는 결과테이블과 테이블의 행을 가리키는 커서를 가지고있습니다.
이 커서는 처음 ResultSet에 결과를 받아 할당해주면 테이블의 첫번째 행의 이전을 가리키도록 되어있습니다.

먼저 ResultSet의 주요 메서드를 보겠습니다.

 메서드명(파라메터)

리턴타입 

기능 

  first()

 boolean

  커서를 첫번째로 이동합니다.

  last()

boolean

 커서를 마지막으로 이동합니다.

  next()

boolean

 커서를 다음으로 이동합니다.

  previous()

 boolean

 커서를 이전으로 이동합니다.

  absolute(int row)

 boolean

 커서를 선택한 행으로 이동합니다.

  isFirst()

 boolean

 현재 커서가 첫번째 행에 있는지 확인합니다.

  isLast()

 boolean

 현재 커서가 마지막 행에 있는지 확인합니다. 

  get<G>(String columnLabel)

 <G>

  JDBC 기본자료형과 맞는 형식의 타입으로 SQL문에서 조회된 컬럼명을
  기준으로 값을 가져옵니다.

  get<G>(int columnIndex)

 <G>

  JDBC 기본자료형과 맞는 형식의 타입으로 SQL문에서 조회된 컬럼의
  순서(Index)를 기준으로 값을 가져옵니다.

  close()

void 

  ResultSet 인스턴스를 닫습니다.(해제)



위의 Statement와 PreparedStatement의 주요 메서드를 살펴보면서
ResultSet형식을 반환하는 executeQuery라는 메서드들 살펴보았습니다.

먼저 ResultSet또한 멤버 필드로 등록하여 사용하는것이 편한 인터페이스입니다.

지금까지 알아본 Connection과 Statement,PreparedStatement 그리고 지금 알아보는 ResultSet은 다 같이 멤버로 사용하는 것이 편합니다.

import java.sql.Connection;
import java.sql.Statement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

private Connection conn = null;
private Statement 
stmt = null;
private PreparedStatement pstmt = null;
private ResultSet rs = null;


이렇게 선언하고 rs라고 하겠습니다.

rs는 결과를 받는 객체입니다.

결과를 받는 방법은 간단합니다. stmt의 결과를 받는 예들 들면,

query = "SELECT * FROM test_table";

rs = stmt.executeUpdate(query));


이 경우 query에 들어있는 "SELECT * FROM test_table"라는 SQL문의 결과가 rs에 저장됩니다.

간단하게 test_table에는 위에서 설명했듯이 아래와 같은 구조로 데이터가 들어가있습니다.

num - INT
name - VARCHAR
value - INT

num 

name 

temp 

 1

 "aa" 

 0

 2

 "bb" 

 1



ResultSet을 사용하기전 중요한걸 한가지 알고 넘어가야 합니다.


바로 JDBC타입과 Java자료형의 호환성에 대해 알고가셔야하는데요.

자바를 자주 공부하시는 분이라면 아래 링크를 꼭 북마킹(또는 즐찾)해주시길 권장드립니다.





지금 사용해야 할 JDBC라는 것은 자바와 DB를 연결 하는 인터페이스 라고 말씀드렸습니다.

현재 우리가 알아야할 예제에서는 Mysql타입 중 INT형과 VARCHAR형만 사용되었습니다.

그럼 MySQL 타입의 INT와 VARCHAR는 자바 자료형중 어떤 자료형에 담아야할까요?


INT - java.lang.Integer

VARCHAR - java.lang.String

각각 위 자료형들과 연결을 해줘야합니다.

더 자세한 연계는 제가 공유해드리는 링크를 참조해주시길 바랍니다.


자료형의 관계에 익숙해지시면 rs객체를 사용하는 방법 또한 간단합니다.

먼저 ResultSet의 가장 기본적으로 사용되는 방법은 boolean형식으로 리턴되는 next()라는 메서드를 통해 사용이 가능합니다.


private Integer[] nums = new Integer[2];
private String[] names = new String[2];
private String[] values = new String[2];


int i = 0;

while(rs.next()) 
{
    nums[i] = rs.getInt(1); // 1번째 컬럼값은 1번으로 받아옵니다. //rs.getInt("no"); 형식으로 사용할 수 있습니다.
    names[i] = rs.getString(2);  // 마찬가지로 rs.getString("name"); 형식으로 사용할 수 있습니다.
    values[i] = rs.getString(3);  // rs.getString("value");
    i++;
}

그리고 앞서 나왔던 각 컬럼값의 타입(MySQL의 자료형)과 매칭되는 Java의 자료형에 맞는 getter 메소드를 사용하여 적절하게 이용하시면

ResultSet의 기본적인 사용법은 끝입니다.



이것으로 가장 기본적인 JDBC를 사용하는 방법을 알아보았습니다.


감사합니다.

'Development > Java' 카테고리의 다른 글

[Java기초] 03.Statement와 PreparedStatement 차이  (0) 2014.11.25
[Java기초] 01.JDBC연결하기  (3) 2014.11.25
[Easy Java] 01.hashCode란?  (0) 2014.11.23