japanese site
온라인강좌책메일다운로드동아리쇼핑기술지원기업정보갤러리동영상 블로그
『신개념 4단계 리눅스기술지원 시스템 공개』

※ 『무료 리눅스 배포판 배송서비스』 ※

 
JDBC를 익히자
조회 : 2,323  


김세곤 <sehkone@bawi.org>

2000년 4월 18일

개요

  JDBC란

근래 웹 개발에서 데이터베이스 연동은 빼 놓을 수 없는 요소이다. 몇 년 전까지만 해도 데이터베이스를 이용한 개발은 큰 프로젝트에서나 수행하는 과정이었는데, 요즘은 데이터베이스 없이 파일 처리만으로 뭔가를 개발하는 일은 거의 불가능해 보인다. 데이터베이스가 이렇게 일반적으로 누구나 사용할 수 있게 된 것은 우선, postgreSQL, mySQL과 같이 정말로 쓸만한 데이터베이스가 무료로 배포가 되고 있다는 사실 때문이고, 다음으로는 데이터베이스 조작이 여러가지 인터페이스를 통해 쉬워졌다는 이유 때문이다.

Java는 여타 다른 개발 환경보다도 훨씬 쉽고 강력한 데이터베이스 조작 인터페이스를 제공하는데 이것이 JDBC이다. JDBC 2.0에 이르러서는 많은 함수들이 추가되어 사용하는데 불편이 거의 없다. 더불어, 어떤 데이터베이스를 쓰더라도 JDBC 드라이버만 제공된다면 코드의 수정이 거의 없이 바로 적용이 가능하다는 막강한 장점이 있다. Java을 사용하여 데이터베이스를 다루는 것이 여타의 환경에 비해 강력하고 편하다는 이薩穗?이 글에서는 구구절절이 늘어놓지 않기로 하고, 실제 JDBC로 데이터베이스를 접근하려고 결정한 개발자가 쉽게 JDBC의 기능을 익힐 수 있도록 API 사용법을 중심으로 설명하겠다.

데이터베이스에 접속

  드라이버 로딩

JDK에는 JDBC를 위한 java.sql.* 클래스들이 있다. JDBC 2.0 표준 외에 근래에 몇 가지 기능이 추가된 Standard Extension API를 담고 있는 javax.sql.* 클래스들이 있는데 이 글은 우선 java.sql.* 클래스를 위주로 설명하도록 하겠다. 이 클래스는 JDBC API의 인터페이스 정의에 대한 것만 담고 있을 뿐, 개별 데이터베이스(예를 들면 오라클, postgreSQL)와는 무관하다. 따라서, Java가 제공하는 JDBC API를 사용하기 위해서는 개별 데이터베이스에 맞게 구현된 드라이버가 있어야만 한다. 거의 대부분의 데이터베이스가 JDBC 드라이버를 지원하므로 각 사이트에서 알맞은 것을 다운 받으면 된다. 주의할 점은 JDBC 2.0 스펙은 JDK 1.2 이상에서만 사용할 수 있으므로, 자신의 JDK 버전에 알맞은 드라이버를 설치해야 한다. 데이터베이스 제조회사 측, 혹은 third party측에서 제공하는 외부 드라이버를 설치한 후, JDBC를 사용하기 위해서는 외부에서 지원되는 드라이버를 사용할 수 있도록, 소스에 그 드라이버 이름을 명시해 주어야 한다. 따라서, 모든 JDBC를 사용하는 Java 프로그램은 다음처럼 JDBC API를 사용하기 전에 드라이버 이름을 명시하는 작업을 수행해야 한다. (javax.sql.* 클래스를 이용한다면 다른 방법으로 접근한다)



import java.sql.*;
import java.lang.*;

public class Test {
    public static void main(String[] args) {
        try {
            Class.forName("myDriver.ClassName");
        } catch (ClassNotFoundException e) {
            System.err.println("Class Not Found : " + e.getMessage());
        }
    }	
}

가운데 Class.forName의 인자로 myDriver.ClassName 대신 자신의 데이터베이스가 제공하는 드라이버 이름을 명시하면 된다. postgreSQL이라면 postgresql.Driver라고 적어 넣으면 된다. 이제, JDBC 드라이버를 사용할 준비는 모두 되었고, 본격적인 JDBC API 사용법을 익히자.

  접속하기

데이터베이스와의 접속을 관장하는 클래스는 Connection이다.



import java.sql.*;
import java.lang.*;

public class Test {
    public static void main(String[] args) {
	// 드라이버 로딩
        try {
            Class.forName("myDriver.ClassName");
        } catch (ClassNotFoundException e) {
            System.err.println("Class Not Found : " + e.getMessage());
        }
	// 데이터베이스 접속
	try {
	    String url = "jdbc:myprotocol:mydatabase";
            Connection db = DriverManager.getConnection(url, "myid", "mypassword");
        } catch (SQLException e) {
            System.err.println("SQL Error : " + e.getMessage());
        }
    }	
}

getConnection()함수의 인자를 살펴보자. 첫번째 인자는 데이터베이스의 프로토콜과 데이터베이스 이름을 알려준다. 이 인자의 처음 두 단어는 JDBC 드라이버에 따라 일정하다고 보면 되고, 마지막 단어는 접속할 데이터베이스의 이름을 나타낸다. postgreSQL을 쓴다면 처음 두 단어는 jdbc:postgresql이 된다. getConnection() 함수의 두 번째 인자는 접속하려는 데이터베이스의 권한을 갖고 있는 아이디이고 세 번째 인자는 이 아이디의 비밀번호이다. 이제, Connection 클래스의 instance인 db는 명시한 데이터베이스의 접속하였으며 JDBC의 API를 이용하여 작업을 수행할 일만 남았다.

SQL 사용하기

  Statement 클래스

이제, 데이터베이스를 조작하기 위해서는 접속한 데이터베이스에 적절한 SQL 구문을 실행시키면 된다. JDBC는 SQL 구문 처리를 위해 두 가지 클래스를 준비하고 있다. Statement 클래스와 PreparedStatement 클래스가 그 두 가지인데, 우선 Statement 클래스를 살펴보자. 간단히 예제를 보자.



1  import java.sql.*;
2  import java.lang.*;
3 
4  public class Test {
5     public static void main(String[] args) {
6	 // 드라이버 로딩
7         try {
8             Class.forName("myDriver.ClassName");
9         } catch (ClassNotFoundException e) {
10             System.err.println("Class Not Found : " + e.getMessage());
11        }
12
13        try {
14	      // 데이터베이스 접속
15   	      String url = "jdbc:myprotocol:mydatabase";
16            Connection db = 
17                  DriverManager.getConnection(url, "myid", "mypassword");
18	
19	      // SQL문 수행
20	      Statement stmt = db.createStatement(); 
21	      ResultSet rs = stmt.executeQuery("SELECT id FROM member");
22        
23            .......
24	
25        } catch (SQLException e) {
26            System.err.println("SQL Error : " + e.getMessage());
27        }
28     }	
29  }

Connection 클래스의 createStatment 메쏘드가 SQL 구문 처리를 위한 Statement 클래스의 인스턴스 생성을 수생하므로, Statement로 SQL 구문 처리를 위해서는 언제나 20번 행과 같이 Statement의 인스턴스를 Connection으로부터 생성해야 한다.

Statement 클래스의 메쏘드 중에서 SQL 구문을 처리하는 것 중 자주 쓰이는 것은 executeQuery(), executeUpdate() 두 가지가 있다. 두 메쏘드의 인자로는 모두 SQL 구문을 표현하는 String 값이다. executeQuery()는 SELECT와 같이 결과 값이 있는 경우에 사용되고, executeUpdate()는 INSERT, UPDATE와 같이 데이터베이스의 내용을 바꾸고 결과 값이 없는 경우에 사용된다. 두 메쏘드 모두 사용하는 데이터베이스가 이해할 수 있는 SQL 구문을 인자로 넘겨주면 문제없이 수행된다. 코드 호환성을 위해서는 되도록 표준 SQL을 사용하도록 하자.

가장 많이 쓰이는 SQL 구문인 SELECT의 경우는 그 결과를 처리해야 한다. JDBC는 SELECT를 통해 얻어지는 결과를 ResultSet 클래스를 통해 접근하도록 하고 있다. ResultSet에 대해서는 다음 다음 절을 통해 살펴보자.

  PreparedStatement 클래스

"SELECT name FROM member WHERE id = 'me'"와 같은 구문은 WHERE 절의 'me' 부분만 변경하여 자주 사용될 수 있다. 어떤 경우는 loop문으로 인자만 변경하여 똑같은 SQL 문을 수행하는 경우도 있다. 이처럼 인자만 변하고 구문이 같을 경우 JDBC는 구문 생성 및 컴파일 시간을 단축시킬 수 있도록 PreparedStatement 클래스를 제공하고 있다. PreparedStatement 클래스는 같은 코드 내에서 여러번 수행되는 구문에 적용하면 수행 속도 향상을 꾀할 수 있고, 오직 한 번만 수행되는 구문이라고 해도 필자의 경우는 코딩이 깔끔해서 Statement 구문보다 더 선호한다. 예제를 보자.



1  import java.sql.*;
2  import java.lang.*;
3 
4  public class Test {
5     public static void main(String[] args) {
6	 // 드라이버 로딩
7         try {
8             Class.forName("myDriver.ClassName");
9         } catch (ClassNotFoundException e) {
10             System.err.println("Class Not Found : " + e.getMessage());
11        }
12
13        try {
14	      // 데이터베이스 접속
15   	      String url = "jdbc:myprotocol:mydatabase";
16            Connection db = 
17                  DriverManager.getConnection(url, "myid", "mypassword");
18	
19	      // SQL문 수행
20	      PreparedStatement stmt = db.prepareStatement(
21                    "SELECT name FROM member WHERE id = ?");
22            stmt.setString(1, "me");
23	      ResultSet rs = stmt.executeQuery();
24            
25            .......         
26      
27            stmt.setString(1, "you");
28	      rs = stmt.executeQuery();
29            .......
30	
31        } catch (SQLException e) {
32            System.err.println("SQL Error : " + e.getMessage());
33        }
34     }	
35  }

Statement는 Connection의 createStatement() 메쏘드로 인스턴스를 생성하였는데, PreparedStatement는 prepareStatement() 메쏘드로 인스턴스를 생성한다. createStatement() 메쏘드는 인자가 없지만 prepareStatement() 메쏘드는 인자가 있다. 이 인자는 생성하려는 SQL 구문의 골격을 나타내는 것으로서 변경하고자 하는 인자를 ? 로 표현한 형태여야 한다. 21번 행에서는 id 값을 인자로 설정하여 id = ? 와 같이 표현하였다. 데이터베이스 필드의 타입과 상관없이(문자열, 정수, 실수 상관없이) ? 로 나타내면 된다.

이제, 생성된 SQL 구문 중 ? 로 표시한 인자에 값을 지정해 주어야 한다. 이를 위해 PreparedStatement 클래스는 setXXX() 메쏘드를 제공한다. XXX 부분은 필드의 타입에 따라 무척 많은데, 예를 들면 setString(), setInt(), setDouble() 등이 있다. 이 setXXX 메쏘드의 첫번째 인자는 ?의 위치를 나타낸다. prepareStatement() 메쏘드로 생성한 SQL 구문 골격에는 ?가 복수로 들어갈 수 있는데, 좌측 첫번째가 1로 시작하여 ?의 위치가 표현된다. setXXX() 메쏘드의 두 번째 인자는 지정한 인자의 값이다. 타입에 맞는 값이 넘겨져야 한다.

setXXX() 메쏘드로 인자가 모두 설정되었다면 Statement 클래스를 수행하는 것처럼 executeQuery() 혹은 executeUpdate()를 사용하여 구문을 직접 데이터베이스에 던져 수행하면 된다. PreparedStatement 클래스는 Statement 클래스를 계승하므로 executeXXX() 메쏘드는 그 동작이 동일하다.

  ResultSet 클래스

SELECT와 같은 SQL 구문을 통해 얻어지는 결과는 ResultSet 클래스가 다룬다고 하였다. 이 클래스의 사용법을 알아보자. Statement 클래스 혹은 PreparedStatement 클래스의 executeQuery() 메쏘드의 리턴 값이 ResultSet 클래스 타입인 것은 앞서의 예제를 보면 쉽게 알 수 있다.

SELECT와 같은 구문을 통해 얻어지는 결과는 복수 개의 tuple이다. 그리고 개별 tuple에는 복수 개의 field가 있다. 따라서, ResultSet 클래스는 복수 개의 tuple 사이를 이동하는 메쏘드들과 현재 tuple의 특정 filed 값을 얻는 메쏘드들을 제공한다. 우선, tuple을 이동하는 메쏘드를 살펴보자. tuple 사이를 이동하는 포인터와 같은 역할을 하는 것을 흔히 cursor라 부른다. 이 cursor의 위치를 움직이는 메쏘드로는 next(), previous(), first(), last() 등이 있다. 이 네 가지 외에도 몇 가지가 있는데 자세한 사용법은 API Reference를 참조하면 쉽게 알 수 있다. 메쏘드의 이름에서 충분히 그 역할을 짐작할 수 있다.

현재의 cursor 위치에 해당하는 tuple의 field 값을 얻는 함수로는 getXXX() 메쏘드들이 있다. XXX는 얻고자 하는 field의 타입을 표현한다. 예를 들면 문자열이라면 getString, 정수 값이라면 getInt 등이다. 이 getXXX() 메쏘드의 인자로는 얻고자 하는 field의 이름이나 순서상의 위치 값이 들어가면 된다. 예제를 보도록 하자.



1      Connection db = 
2             DriverManager.getConnection(url, "myid", "mypassword");
3	
4      Statement stmt = 
5             db.createStatement("SELECT name, age FROM member");
6      ResultSet rs = stmt.executeQuery();
7
8      while (rs.next()) {
9          String name = rs.getString("name");
10         String age = rs.getInt("age");         
11         System.out.println(name + ":" + age);
12     }

8번 행에서는 cursor의 위치를 하나씩 다음으로 움직이는 next() 메쏘드를 사용하였다. cursor를 움직이는 메쏘드들은 더 이상 움직일 수 없을 때 false를 리턴하므로 이처럼 while 문을 사용하면 얻어지는 tuple을 모두 하나씩 살필 수 있다. 9번과 10번 행에서는 getXXX() 메쏘드의 사용예를 알 수 있다. 인자로 SQL 구문에서 사용한 field 이름을 사용하였다. getString("name") 대신 getString(1), getInt("age") 대신 getInt(2)와 같은 식으로 인자의 위치를 정수로 표현해도 되지만, field의 이름을 직접 적어 주도록 하자. SQL 구문을 조금 변화시켜도 getXXX() 메쏘드의 인자를 위치로 표현했다면 수정해야 하기 때문에 이름으로 사용하는 것이 훨씬 편리하다.

참고

  close로 닫기

Java는 메모리 관리를 따로 하지 않아도 자체적으로 garbage collection 기능이 있어 사용되지 않는 객체는 자동적으로 처리된다. 그러나, Sun은 JDBC 드라이버와 같이 외부 지원되는 드라이버에 대해서는 생성된 객체를 코드 내에서 소멸시키도록 권장하고 있다. JDBC API는 이를 위해 close() 메쏘드를 제공하는데, close() 메쏘드를 사용해야 할 클래스는 Connection, Statement, PreparedStatement, ResultSet 등이다. 따라서, 데이터베이스에 접속하여 SQL 구문을 모두 수행했다면 다음처럼 close() 메쏘드를 사용하여 객체를 모두 소멸시키도록 한다.



     stmt.close();
     rs.close();
     db.close();

  JSP 파일에서 데이터베이스 사용

JSP에서는 일반 Java 코드에서 JDBC를 사용하는 것과 다를 바가 없다. 다만 java.sql.* 클래스를 import 하는 것을 잊지 말아야 하는데, 이는 JSP 파일 상단에 다음처럼 적어주면 된다.

<%@ page import="java.sql.*" %>

  about Performance

데이터베이스 수행 중에 가장 성능에 영향을 주는 것은 접속과 해제이다. Connection 클래스로 데이터베이스에 접속하는 것은 매우 heavy한 일로서 웹 개발처럼 클라이언트가 접속할 때마다 데이터베이스에 접속하였다가 해제하도록 하는 것은 피해야 한다. 이를 위해 데이터베이스 접속을 pool로 관장하는 방법이 일반적인데, J2EE 기반이라면 javax.sql.* 클래스를 사용하여 간단하게 데이터베이스 접속을 pool로 관리할 수 있지만, J2SE 기반이라면 singlet 등을 사용해야 한다. 데이터베이스 접속을 pool로 관리하는 방법이나 J2EE 환경에 대한 설명은 이 글의 범주를 벗어나므로 다음 기회로 미루겠다.


[원글링크] : https://www.linux.co.kr/home2/board/subbs/board.php?bo_table=lecture&wr_id=598


이 글을 트위터로 보내기 이 글을 페이스북으로 보내기 이 글을 미투데이로 보내기

 
雍섟

 
   
 


『신개념 4단계 리눅스기술지원 시스템 공개』

CentOS 리눅스 전문서적 국내최초출시

 
회사소개 | 보도기사 | 채용안내 | 광고안내 | 이용약관 | 개인정보취급방침 | 책임한계와 법적고지 | 불편사항 신고하기 | 사이트맵
ㅇ 서울 : 서울특별시 강남구 노현로79길 66, 402호(역삼동,청송빌딩)  ㅇ 부산 : 부산광역시 해운대구 우동 1470 에이스하이테크21 914호
ㅇ 대표 : 1544-8128 ㅇ부산직통 : 051-744-0077 ㅇ서울직통 : 02-856-0055 ㅇ FAX : 02-6280-2663
ㅇ 사업자번호 : 128-86-68239 ㅇ 통신판매업 신고번호 : 2013-부산금정-0035호 ㅇ 개인정보책임자 : 이재석
ㅇ 상호명 : (주) 수퍼유저 ㅇ 대표자 : 박성수
Copyright ⓒ (주)수퍼유저. All rights reserved.

 아 이 디
 비밀번호
회원 가입 | 비밀번호 찾기

블로그~
 
▷ 웹개발언어
PHP
JSP
python
기타
책제목
리눅스서버관리실무바이블v3.0


저자 박성수
페이지수 2,032 pages
펴낸곳(주)수퍼유저

리눅스 서버 구축 및 관리에 필요한 거의 모든 부분과 전반적인 실무 기법들을 다루고 있음
책제목
리눅스보안관리실무(2/E)


저자홍석범
페이지수 820 pages
펴낸곳(주)수퍼유저

리눅스 보안에 관련된 내용을 종합적으로 쓴 책. 저자의 명성 그대로 보안관련의 모든 내용이 그대로 담겨져 있다.