[czar] 2010. 11. 5. 10:10

JDBC Driver 종류
 ** 타입1과 2는 순수 자바 드라이버가 지원이 안될때 사용하고 타입3과 4는 JDBC API를 통해 데이타베이스에 접근한다

 타입 1: JDBC ODBC Brige + ODBC Driver
   ODBC 드라이버를 통해 데이타베이스에 접근
 타입 2: Native API partly Java Driver
   C 로 작성된 자체 함수 인터페이스를 통해 데이타베이스에 접근
 타입 3: JDBC Net pure Java Driver
   미들 티어 서버를 통해 데이타베이스에 접근
 타입 4: Native protocol pure Java Driver
   데이타베이스 벤더가 제공하는 순수 자바 코드로 이루어진 JDBC 드라이버로 직접 데이타베이스에 접속
   일반적으로 가장 많이 사용하는 드라이버이다

JDBC API
 ** 데이타베이스의 테이블 구조를 모르더라도 메타데이타를 통해 데이타베이스를 사용할 수 있다
 ** java.sql 패키지를 사용한다
 ** 좀 더 상세한 정보는 해당 API로 확인한다

 인터페이스
  Connection      JDBC API를 통한 데이타베이스 연결
  DatabaseMetaData     시스템 Catalog, Key, Table, Transaction에 관련된 사항둥 해당 데이타베이스에 관한
                       포괄적인 정보를 제공
  ResultSetMetaData    ResultSet 객체의 칼럼에 대한 타입과 프로퍼티 정보를 가져올 수 있는 인터페이스로
         테이블의 칼럼 정보를 제공
  ResultSet      Statement 객체를 통해 데이타베이스에 전송된 SQL문에 의해 반환되는 데이타
  Statement      SQL문을 데이타베이스에 전송
  PreparedStatement    반복되는 SQL문을 미리 컴파일 한 뒤 데이타베이스에 전송
  CallableStatement    데이타베이스 내부의 스토어드 프로시저를 호출하기 위한 인터페이스
 클래스
  DriverManager      JDBC 드라이버들을 관리
  Types       SQL 데이타 타입 선언

 1. Conection
  Statement createStatement()                       /* Statement 객체 생성 */
  PreparedStatement preparedStatement(String sql)   /* PreparedStatement 객체 생성 */
  CallableStatement prepareCall(String sql)         /* CallableStatement 객체 생성 */

  Transaction 처리
   메소드
    setAutoCommit(boolean autoCommit)
     - 데이타베이스 연결에 대한 자동 커밋 모드를 설정/해제 한다
     - 데이타베이스에 대한 새로운 연결이 생성되면 기본적으로 자동 커밋 모드로 설정되기 때문에
       매번 SQL문이 수행될 때마다 자동 커밋을 수행한다
     - 자동 커밋 모드를 해제했을 경우에는 SQL문 수행후 commit()을 명시적으로 호출하지 않으면
       처리 결과가 데이타베이스에 반영되지 않는다
    getAutoCommit()                   
     - 현재 설정되어 있는 자동 커밋 모드를 얻는다
    commit()                          
     - 작업 이후 발생한 모든 변경 사항을 커밋하여 데이타베이스에 반영하고 데이타베이스에 대한 락을 해제한다
       자동 커밋 모드를 해제했을 경우에만 사용할 수 있다
    rollback()                        
     - 작업 이후 발생한 모든 변경 사항을 취소하고 데이타베이스에 대한 락을 해제한다
       자동 커밋 모드를 해제했을 경우에만 사용할 수 있다

   작업 순서
    ** 트랜잭션을 관련있는 작업 단위로 처리하고자 한다면 autoCommit을 false로 하고 사용자가 판단하는 시점에
       commit()이나 rollback()을 처리 해서 트랜잭션을 종료한다
    ** 작업 수행중 예외가 발생하면 작업 이후 변경된 내용을 작업하기 이전으로 rollback해야 한다

    예제
     try
         {
         Connection con = DriverManager.getConnection();  /* 커넥션을 얻는다 */
         Statement stmt = con.createStatement();

         con.setAutoCommit(false);        /* 자동 커밋 모드를 끈다 */
         stmt.executeUpdate();                            /* SQL문을 수행한다 */
         con.commit();         /* 커밋한다 */
         }
     catch (Exception e)
         {
         con.rollback();         /* 롤백한다 */
         }
     finally
         {
         stmt.close();
         con.close();                                     /* 커넥션을 닫는다 */
         }

 2. DatabaseMetaData
  ResultSet getCatalogs()   서버의 데이타베이스 리스트  
  ResultSet getSchemas(...)  서버의 사용자 리스트
  ResultSet getTables(...)  데이타베이스 테이블 리스트
  ResultSet getColumns(...)  테이블의 칼럼 리스트
  ResultSet getPrimaryKeys(...)  기본 키 리스트
  ResultSet getIndexInfo(...)  인덱스 리스트

 3. ReslutSetMetaData
  String getColumnName(int column)        칼럼명
  int getColumnType(int column)           칼럼의 SQL 타입
  int getColumnDisplaytSize(int column)   NCHAR/NVARCHAR일 경우에는 *2
  int getColumnCount()                    테이블 칼럼의 갯수
  int getScale(int column)                소수점 이하 자리수
   
 4. ResultSet
  ** SELECT SQL문의 실행 결과로서 생성된 결과에 해당하는 테이블
  ** Statement를 닫을때, 다른 SQL을 실행할때, 여러 개의 결과를 생성한 상태에서 getMoreResults를 호출하면
     이미 생성된 ResultSet은 내부적으로 자동으로 close된다

  void close()    ResultSet 닫기
  boolean first()    ResultSet의 첫번째 레코드로 이동
  bollean last()    ResultSet의 마지막 레코드로 이동
  boolean next()    다음 레코드로 이동
  boolean previous()   이전 레코드로 이동
  boolean wasNull()   칼럼의 값이 NULL인지 검사
 
  int getInt(칼럼)   int
  long getLong(칼럼)   long
  double getDouble(칼럼)   double
  String getString(칼럼)   String
  Timestamp getTimestamp(칼럼)  날짜/시간/시분초
  byte[] getBytes(칼럼)   binary, varbinary
  Reader getCharacterStream(칼럼)  clob, longvarchar
  InputStream getBinaryStream(칼럼) blob, longvarbinary

  예제
   Statement stmt = Connection.createStatement();  
   ResultSet rs = stmt.executeQuery("slect 칼럼1, 칼럼2, 칼럼3, 칼럼4 from 테이블명");
   while (rs.next())
       {
       int i = rs.getInt(칼럼1);
       String s = rs.getString(칼럼2);

       Reader c_in = rs.getCharacterStream(칼럼3);
       char[] c_buffer = new char[4096];
       StringBuffer c_s = new StringBuffer();
       int c_read;
       while ((c_read = c_in.read(buffer, 0, 4096)) != -1) c_s.append(c_buffer, 0, c_read);

       InputStream b_in = rs.getBinaryStream(칼럼4);
       byte[[] b_buufer = new byte[4096];
       int b_read;
       while ((b_read = b_in.read(b_buffer, 0, 4096)) != -1) b_s.append(toHexString변환(b_buffer), 0, b_read);
       }

 5. Statement
  ** Statement는 오직 하나의 ResultSet만 생성하기 때문에 ResultSet 객체를 읽는 도중에 다른 ResultSet을 읽어야
     한다면 반드시 서로 다른 두개의 Statement 객체가 필요하다
  ** Statement의 메소드를 실행하기 전에 이미 열려 있는 ResultSet 객체가 있으면 닫아야 한다

  ResultSet executeQuery(String sql)
   단일 ResultSet을 리턴한다
  int executeUpdae(String sql)
   insert, delete, update등과 같이 데이타베이스를 변경하여 갱신하는 작업을 한다
  boolean execute(String sql)
   여러 개의 ResultSet, update count를 리턴한다

   boolean getMoreResults()  
    리턴 결과가 ResultSet이면 true를 결과가 없거나 변경된 갯수이면 false이다
    getMoreResults가 false이고 getUpdateCount가 -1이면 더 이상 결과가 없다는것을 의미한다
   ResultSet getResultSet()  
    현재 결과에 해당하는 ResultSet을 얻는다
   int getUpdateCount()   
    변경된 데이타의 갯수를 리턴한다
    -1이면 변경된 데이타가 없거나 결과가 ResultSet이라는것을 의미한다

 6. PreparedStatement
  ** Statement 상속한다
  ** 파라미터를 넘겨줄때는 칼럼의 타입과 일치하는 메소드를 사용해야 하지만 일반적으로 setString을 사용해도 상관없다

  ResultSet executeQuery()         ResultSet을 리턴한다
  int executeUpdate()              실행 결과 값을 리턴한다
  boolean execute()                여러개의 결과를 리턴한다
  ResultSetMetaData getMetaData    ResultSetMetaData를 리턴한다

  예제
   PrepatedStatement pstmt = Connection.preparedStatement("update 테이블명 set 칼럼1=? where 칼럼2=?");
   pstmt.setString(1, "값1");
   pstmt.setString(2, "값2");
   pstmt.executeUpdate();

 7. CallableStatement
  ** PreparedStatement 상속한다
 
  void registerOutParameter(int parameterIndex, int sqlType)
   주어진 위치에 해당하는 파라미터를 sqlType을 갖는 out 파라미터로 등록한다
  void registerOutParameter(int parameterIndex, int sqlType, int scale)
   파라미터 타입이 numeric이나 decimal일 경우 소수점 자리수를 지정한다

  파라미터가 있는 프로시저        { call 프로시저명(?, ?, ... ) }
  결과 값을 리턴하는 프로시저(Function)  { ? = call 프로시저명(?, ?, ...) }
  파라미터가 없는 프로시저        { call 프로시저명 }

  예제
   CallableStatement cstmt = Connection.prepareCall("{ call 프로시저명(?, ?) }");
   cstmt.setString(1, "값1");
   cstmt.registerOutParameter(2, java.sql.Types.INTEGER);
   cstmt.executeQuery();
   int 리턴값 = cstmt.getInt(2);
   
SQL 데이타 타입
 ** JDBC에서 사용하는 데이타 타입은 크게 4가지로 나뉘어 진다
    정수:      BYTE, SHORT, INT, LONG
    실수:      FLOAT, DOUBLE
    문자:      CHAR, VARCHAR
    날짜/시간: DATE, TIME, TIMSTAMP

 java.sql.Types  Oracle   MSSQL   MySql   java.sql.ResultSet
 ---------------------------------------------------------------------------------------------------------------------
 LONGVARCHAR  LONG   TEXT/NTEXT  TEXT   getCharacterStream
 CLOB   CLOB      LONGTEXT

 LONGVARBINARY  LONG RAW     BLOB  
 BLOB   BLOB      LONGBLOB  getBinaryStream

 TINYINT      TYNYINT   TINYINT    
 SMALLINT     SMALLINT  SMALLINT  
 INTEGER      INT   INTEGER/INT  getInt
 BIGINT   NUMBER   BIGINT   BIGINT   getLong

 BIT      BIT      
 BOOLEAN            getByte

 DECIMAL      DECIMAL   DECIMAL
 NUMERIC      NUMERIC                                        
 FLOAT      FLOAT   FLOAT  
 REAL      REAL
 DOUBLE   NUMBER(p, s)     DOUBLE   getDouble

 CHAR   CHAR/NCAHR  CHAR/NCHAR  CHAR
 VARCHAR   VARCHAR2/NVARCHAR2 ARCHAR/NVARCHAR  VARCHAR   getString

 BINARY      BINARY
 VARBINARY  RAW(n)   VARBINAR/IMAGE     getBytes

 DATE   DATE   SMALLDATETIME  DATE   getDate
 TIME         TIME   getTime
 TIMESTAMP  TIMESTAMP  DATETIME  DATETIME/TIMESTAMP getTimestamp 
 ---------------------------------------------------------------------------------------------------------------------
 ** sql.Types.CLOB, Types.LONGVARCHAR일 경우 MySql은 getString으로 Oracle, MSSQL은 getCharacterStream으로 처리한다
    sql.Types.LONGVARBINARY, sql.Types.BLOB은 getBinaryStream으로 처리한다
    sql.Types.NUMERIC, sql.Types.DECIMAL일 경우 소수점이 없으면 getLong을 사용한다
    sql.Types.BINARY, sql.Types.VARBINARY는 바이트 배열(Byte[])로 데이타를 읽어온다

 Oracle      MSSQL     MySql
 ---------------------------------------------------------------------------------------------------------------------
 LONG            2 GB        TEXT          65535*2 Byte
 CLOB            4 GB    TEXT/NTEXT   8000 Byte 이상        LONGTEXT      4 GB

 RAW(n)            n 바이트
 LONG RAW           2 GB        BOLB          65535*2 Byte
 BLOB            4 GB    IMAGE            8000 Byte 이상        LONGBLOB      4 GB
 BFIL            외부

       TYNYINT          1 Byte                TINYINT       1 Byte
              SMALLINT   2 Byte                SMALLINT      2 Byte
       INT    4 Byte                INTEGER/INT   4 Byte
 NUMBER             숫자    BIGINT           8 Byte 정수           BIGINT        8 Byte

       BIT    1 Byte(0, 1)

       MONEY/SAMLLMONEY 화페   FLOAT         4 Byte
       NUMERIC/DECIMAL  고정 소수점           DECIMAL      
   NUMBER(p, s)    p전체 s소수점 이하    FLOAT/REAL   부동 소수점           DOUBLE        8 Byte

 CHAR/NCHAR         고정 4000 Byte  CHAR/NCHAR   고정 8000 Byte        CHAR          고정 255 Byte
 VARCHAR2/NVARCHAR2 가변 4000 Byte  VARCHAR/NVARCHAR 가변 8000 Byte        VARCHAR       가변 255 Byte
 
       BINARY/VARBINARY 8000 Byte 이하

 DATE            날짜(시간)            SMALLDATETIME                          DATE/TIME     3 Byte
           TIMESTAMP     4 Byte
 TIMESTAMP          YY/MM/DD/H/M/S/MS     DATETIME         날짜                  DATETIME      날짜(시간)
 ---------------------------------------------------------------------------------------------------------------------
 ** LONG, LONG RAW    ** TABLE                               ** DECIMAL은 소수를 저장하지만
    테이블에 칼럼 하나만 생성      SQL_VARIANT                            내부적으로는 문자 형태로 저장
    2 GB         CURSOR                                 TINYTEXT/TINYBLOB
    SELECT 결과로 데이타를 리턴      UNIQUEIDENTIFIER                       MEDIUMTEXT/MEDIUMBLOB
    데이타를 직접 저장       TIMESTAMP는 레코드가 변경 될 경우      ENUM                 
    처음부터 순차적으로 읽음      자동으로 DB에 유일한 값으로 채워짐     YEAR                 
    TO_LOB() 함수를 사용하여 LOB로 변환      시간과 전혀 관계가 없음
    오브젝트 유형을 지원하지 않음
 ** CLOB, BLOB
    테이블에 여러개의 칼럼을 생성
    4 GB
    SELECT 결과로 위치를 리턴
    데이타를 직접 또는 간접 저장
    랜덤 엑세스가 가능
    LONG, LONG RAW로 변환할 수 없음
    오브젝트 유형을 지원   

JDBC 연결
 ** 한번 로드된 드라이버는 서버를 restart 하지 않는한 메모리에 남아 있는다

 드라이버 클래스
  ** Mssql일 경우 WEB-INF\lib에 sqljdbc.jar(1.5)와, sqljdbc4.jar(1.6)를 같이 복사하지 않는데
     JDK 1.6일 경우 sqljdbc4.jar를 인식하지 못하기 때문이다
     반드시 현재 JDK 버전에 맞는 드라이버만을 복사한다

  Oracle driver:  oracle.jdbc.driver.OracleDriver
         url:     jdbc:oracle:thin:@localhost:1521:XE(XE는 오라클10g express를 설치할때 사용자가 지정한 sid)
           jdbc:oracle:thin:@localhost:1521:oracle9i
               ** JDK 1.6: ojdbc14.jar
           JDK 1.5: ojdbc14.jar
           JDK 1.4: classes12.jar

  Mssql 2005 driver:  com.microsoft.sqlserver.jdbc.SQLServerDriver
      url:     jdbc:sqlserver://localhost:1433;databaseName=AdventureWorks
        2000 driver:  com.microsoft.jdbc.sqlserver.SQLServerDriver
      url:     jdbc:microsoft:sqlserver://localhost:1433;databasename=pubs(databasename=pubs는 작업하는 db 이름)
            ** JDK 1.6: sqljdbc4.jar
               JDK 1.5: sqljdbc.jar
               JDK 1.4: msbase.jar, mssqlserver.jar, msutil.jar

  Mysql driver:  org.gjt.mm.mysql.Driver
        url:     jdbc:mysql://localhost:3306/mysql?useUnicode=true&characterEncoding=euckr(mysql은 작업하는 db 이름)
              ** 버전에 상관없이 mysql-connector-java-5.1.10-bin.jar을 사용한다

 프로퍼티 파일
  ** 데이타베이스 연결 정보를 저장하는 파일 형식이다
    
  db.xml
   ** 웹서버의 홈 디렉토리 c:\inetpub\wwwroot\WEB-INF\classes에 .xml 파일을 보관한다
      multi driver를 기본으로 2개 이상 드라이버를 지정할 수 있다
      Pool 처리를 한번 하고 나면 드라이버가 메모리에 로드되어 있는 상태이기 때문에
      Pool을 해제 하고 싶을 경우나 connection을 추가 수정했을 경우에는 다시 서블릿 컨테이너를 restart 해야 한다
   ** xml 태그는 대소문자를 구분하기 때문에 주의해야 한다

   <?xml version="1.0" encoding="UTF-8"?>
   <property>
    <connection name="oracle10g">
     <driver>oracle.jdbc.driver.OracleDriver</driver>
     <url>jdbc:oracle:thin:@localhost:1521:XE</url>
     <user>system</user>
     <password>xxxx</password>
    </connection>
    <connection name="mssql2005">
     <driver>com.microsoft.sqlserver.jdbc.SQLServerDriver</driver>
     <url>jdbc:sqlserver://localhost:1433;databaseName=AdventureWorks</url>
     <user>sa</user>
     <password>xxxx</password>
    </connection>
    <connection name="mysql51">
     <driver>org.gjt.mm.mysql.Driver</driver>
     <url>jdbc:mysql://localhost:3306/mysql?useUnicode=true&amp;characterEncoding=euckr</url>
      ** xml에서는 &를 참조자로 인식하기 때문에 &를 &amp;로 변경해야 한다
         그래도 sax은 잘려버리는 현상이 생기므로 dom 방식으로 읽어 들여야 한다
     <user>root</user>
     <password>p422755</password>
    </connection>  
   </property>

  db.properties
   ** 웹서버의 홈 디렉토리c:\inetpub\wwwroot\WEB-INF\classes에 .properties 파일을 보관한다
      driver는 하나만 지정할 수 있는데 여러개를 지정해도 마지막에 지정된 driver만 로드된다
      property name(= 이전까지)은 반드시 소문자로, 값(= 이후부터)은 대문자,소문자 상관없다
      값이 없어도 = 은 반드시 써야 한다

   /* MSSQL 2000 */
   drivers=com.microsoft.jdbc.sqlserver.SQLServerDriver
   mydb1.url=jdbc:microsoft:sqlserver://localhost:1433;databasename=pubs
   mydb1.user=sa
   mydb1.password=xxxx
   mydb2.url=jdbc:microsoft:sqlserver://localhost:1433;databasename=northwiind
   mydb2.user=sa
   mydb2.password=xxxx
 
 드라이버 연결
   ** Class.forName()은 JDBC 스펙과 JVM 구현간의 충돌이 일어날 수 있는데
     이것을 피하기 위해서는 Class.forNmae().newInstance()를 사용해야 한다
 
  static Connection getConnection(String url, String user, String password)
   JDBC URL, user, password를 이용하여 데이타베이스 연결을 하고 그 Connection을 리턴한다

  try
      {
      java.lang.Class.forName(st.nextToken().trim()).newInstance();
      java.sql.DriverManager.getConnection(JDBC URL, user, password);
      }
  catch (ClassNotFoundException e)
      {
      throw new Exceptionx("driver not found");
      }
  catch (Exception e)
      {
      throw new Exception(e.getMessage());
      }


부록 데이타베이스 커넥션 풀(DBCP) 소스
 ** dbcp를 통해서 Connection 객체를 얻어왔다면, con.close()를 해주면 된다
    실제적인 db컨넥션이 close 되는게 아니라 DBCP가 Pool 에다가 반납하는 작업이 이루어진다

import java.io.*;
import java.sql.*;
import java.util.*;

import org.apache.commons.pool.impl.*;
import org.apache.commons.dbcp.*;

//*************************************************************
// dbcp를 사용하기 위해서는 다음과 같은 라이브러리가 필요하다
// DBCP API 관련 Jar 파일
// DBCP API가 사용하는 자카르타 Pool API의 Jar 파일
// Pool API가 사용하는 자카르타 Collection API의 Jar 파일
// commons-dbcp-1.2.1 (Commons  DBCP api)
// commons-collections-3.1 (Commons Collection api)
// commons-pool-1.2 (Commons Pool api)
//*************************************************************

public class DBCP
{
    private static DBCP instance = null;

    public static Connection getConnection (String path, String propertyName, boolean autocommit, int type) throws Exception
    {
 Connection con = null;

 if (instance == null)
     {
     synchronized (DBCP.class)
      {
  if (instance == null)
      {
      instance = new DBCP(path, autocommit, type);
      }
  }
            }
 // DBCP일 경우 해당 풀의 커넥션을 가져올 URL은 'jdbc:apache:commons:dbcp:+풀이름'이어야 한다
 // pool에 프로퍼티가 없으면 Configuration file not found 에러메시지가 발생한다
 // 에러메시지를 가로채기 위해서 try catch를 한다.
 try
     {
     con = DriverManager.getConnection("jdbc:apache:commons:dbcp:" + propertyName);
     }
 catch (Exception ex)
     {
     throw new Exceptionx(ex.getMessage());
     }
 return con;
    }

    private DBCP (String path, boolean autocommit, int type) throws Exception
    {
 if (type == Xmls.NONE) init(path, autocommit);
 else                   xmlInit(path, type, autocommit);
    }

    private void init (String path, boolean autocommit) throws Exception
    {
        FileInputStream is;
        Properties dbProps = new Properties();

        try
     {
     is = new FileInputStream(path);
     dbProps.load(is);
     }
 catch (Exception e)
            {
            throw new Exceptionx("파일을 읽을 수 없습니다.");
     }
 loadJDBCDrivers(dbProps);
 createPools(dbProps, autocommit);
     }

     private void loadJDBCDrivers (Properties props) throws Exception
     {
         String driverClasses = props.getProperty("drivers", "sun.jdbc.odbc.JdbcOdbcDriver");
  StringTokenizer st = new StringTokenizer(driverClasses);
  while (st.hasMoreElements())
      {
      String driverClassName = st.nextToken().trim();
      loadDrivers(driverClassName);
             }
      }

      private void loadDrivers (String driverClassName) throws Exception
      {
          try
       {
       Driver driver = (Driver)Class.forName(driverClassName).newInstance();
       DriverManager.registerDriver(driver);
       }
    catch (ClassNotFoundException ex)
       {
              throw new Exceptionx("드라이버를 찾을 수 없습니다.");
       }
    catch (InstantiationException ex)
       {
       throw new Exceptionx("드라이버를 초기화 할 수 없습니다.");
       }
    catch (SQLException ex)
       {
       throw new Exceptionx("드라이버에 에러가 발생했습니다.");
       }
    catch (Exception ex)
       {
       throw new Exceptionx(ex.getMessage());
       }
 }

      private void createPools (Properties props, boolean autocommit) throws Exception
      {
          String[] keys = { ".url", ".user", ".password" };
   String[] propValues;
   String token;

   // getListProperties(...)는 예제에는 없는 메소드임.
   // props를 Vector로 변환하는 메소드인데 자rl만의 방법으로 처리를 할것
   Vector ve = (Vector)getListProperties(props, keys, CodeType.VECTOR);
   for (int i = 0; i < ve.size(); i++)
       {
       token = (String)ve.get(i);
       propValues = (new Stringx(token)).split(Codes.charPart());

       setup(propValues[0].trim(), propValues[1].trim(), propValues[2].trim(), propValues[3].trim(), autocommit);
       }
 }

 /** 속성 설명
  maxActive
   커넥션 풀이 제공할 최대 커넥션 개수
  whenExhaustedAction
   커넥션 풀에서 가져올 수 있는 커넥션이 없을 때 어떻게 동작할지를 지정한다
   1일 경우 maxWait 속성에서 지정한 시간만큼 커넥션을 구할 때 까지 기다리며
   0일 경우 에러를 발생시킨다
   2일 경우에는 일시적으로 커넥션을 생성해서 사용한다
  maxWait whenExhaustedAction
   속성의 값이 1일 때 사용되는 대기 시간. 단위는 1/1000초이며, 0 보다 작을 경우 무한히 대기한다
  maxIdle
   사용되지 않고 풀에 저장될 수 있는 최대 커넥션 개수. 음수일 경우 제한이 없다
  minIdle 사용되지 않고 풀에 저장될 수 있는 최소 커넥션 개수.
  testOnBorrow
   true일 경우 커넥션 풀에서 커넥션을 가져올 때 커넥션이 유효한지의 여부를 검사한다
  testOnReturn
   true일 경우 커넥션 풀에 커넥션을 반환할 때 커넥션이 유효한지의 여부를 검사한다
  timeBetweenEvctionRunsMillis
   사용되지 않은 커넥션을 추출하는 쓰레드의 실행 주기를 지정한다
   양수가 아닐 경우 실행되지 않는다. 단위는 1/1000 초이다
  numTestsPerEvictionRun
   사용되지 않는 커넥션을 몇 개 검사할지 지정한다
  minEvictableIdleTimeMillis
   사용되지 않는 커넥션을 추출할 때 이 속성에서 지정한 시간 이상 비활성화 상태인 커넥션만 추출한다
   양수가 아닌 경우 비활성화된 시간으로는 풀에서 제거되지 않는다
   시간 단위는 1/1000초이다
  testWhileIdle
   true일 경우 비활성화 커넥션을 추출할 때 커넥션이 유효한지의 여부를 검사해서 유효하지 않은
   커넥션은 풀에서 제거한다.
 **/  

 private void setup (String name, String url, String user, String password, boolean autocommit) throws Exception
 {
     // connection pool 생성
     GenericObjectPool conPool = new GenericObjectPool(null);
     // maxActive - 사이트의 최대 커넥션 사용량을 기준으로 지정. 동시 접속자수에 따라서 지정한다
     conPool.setMaxActive(50);
     // minIdle - 사용되지 않는 커넥션의 최소 개수를 0으로 지정하게 되면 풀에 저장된 커넥션의 개수가 0이 될 수 있으며
     // 이 경우 커넥션이 필요할 때 다시 커넥션을 생성하게 된다
     // 따라서 커넥션의 최소 개수는 5개 정도로 지정해두는 것이 좋다
     conPool.setMaxIdle(10);
     // testWhileIdle - 사용되지 않는 커넥션을 검사할 때 유효하지 않은 커넥션은 검사하는 것이 좋다
     conPool.setTestWhileIdle(true);
     // timeBetweenEvctionRunsMillis - 이 값을 알맞게 지정해서 사용되지 않는 커넥션을 풀에서 제거하는 것이 좋다
     // 커넥션의 동시 사용량은 보통 새벽에 최저이며 낮 시간대에 최대에 이르게 되는데
     // 이 두 시간대에 필요한 커넥션의 개수 차이는 수십개에 이르게 된다
     // 이때 최대 상태에 접어들었더가 최소 상태로 가게 되면 풀에서 사용되지 않는 커넥션의 개수가 점차 증가하게 된다
     // 따라서 사용되지 않는 커넥션은 일정 시간 후에 삭제되도록 하는 것이 좋다
     // 보통 10~20분 단위로 사용되지 않는 커넥션을 검사하도록 지정하는 것이 좋다
     conPool.setTimeBetweenEvictionRunsMillis(600000);  // 1/1000초, 600000은 10분이 된다
     // 실제 db와의 커넥션을 연결해 주는 팩토리 생성
     ConnectionFactory conFactory = new DriverManagerConnectionFactory(url, user, password);

     try
         {
  // connection pool이 PoolableConnection 객체를 생성할때 사용할 poolableConnectionFactory 생성
  new PoolableConnectionFactory(conFactory,
        conPool,
        null,   // statement pool
        null,   // 커넥션 데스트 쿼리: 커넥션의 유효성을 테스트할때 사용
        false,  // 읽기 전용 ResultSet을 사용할지 여부. readonly 여부
         // 외부에서 트랜잭션을 별도로 지정을 하면 false로 아니면 true로 지정을 한다
        autocommit);  // 커넥션의 autocommit 여부
  }
      catch (Exception ex)
  {
  throw new Exceptionx(ex.getMessage());
  }
      PoolingDriver driver = new PoolingDriver();
      driver.registerPool(name, conPool);
 }
}