2008. 7. 24. 22:14

JDBC DataSource 인터페이스

1. DriverManager를 통한 Connection 생성의 단점

DriverManager를 통하여 Connection 생성하는 JDBC PROGRAM은 사용하려는 데이터베이스가 변경되거나 그에 따른 JDBC 드라이버가 변경된다면 JDBC PROGRAM의 소스에도 변경되어야 하는 정보가 있음.

JDBC 드라이버 이름과 JDBC URL, 데이터베이스 계정, 데이터베이스 암호등

2. DataSource 인터페이스의 역할

개발자가 어플리케이션 내에서 직접 하드 코딩하지 않으므로 투명한 개발 가능

getConnection 메서드를 이용해 Connection 객체를 생성하는데 이때 접근하는 데이터 소스가 달라도 코드의 수정은 없고, DataSource의 속성값(property)만 변경하여 적용할 수 있음.

DataSource는 JNDI(Java Naming & Directory Interface) 서비스를 제공하는 환경에서 사용 가능

JNDI를 이용한 DataSource를 이용하게 되면 다음과 같은 이점이 있음

*. JDBC PROGRAM 내에서 데이터베이스를 연결할 때에 JDBC 드라이버를 등록할 필요 없음
*. JDBC URL을 몰라도 JDBC 네이밍 서비스와 디렉토리 서비스가 제공하는 기능을 사용할 수 있음

3. DataSource 이용을 위한 Tomcat 엔진의 환경 설정

연결할 데이터베이스의 JDBC 드라이버를 Tomcat 엔진이 설치된 디렉토리의 common\lib 디렉토리에 존재해야 한다. 이 때 JDBC 드라이버 파일은 반드시 확장자 jar 형태로 압축되어 있어야 한다. Tomcat 에서 실행하는 JSP를 통하여 oracle 데이터베이스 9.2.0.1 에 연결하기 위해서는 oracle 데이터베이스 9.2.0.1용의 JDBC 드라
이버를 Tomcat 엔진이 인식하는 classpath로 설정된 디렉토리에 존재해야 한다.

*. http://127.0.0.1:8080/admin 접속한 후 admin 계정으로 로그 인
*. Tomcat Server > Service (Catalina) > Host(loalhost) > Context(/jdbc) > Data Sources 항목 클릭
*. Create New Data Source 클릭
*. 각 Property 입력

Property Value 비고
..JNDI Name ..jdbc/myoracle  
..Data Source URL ..jdbc:oracle:thin:@DB IP:1521:sid ..DB IP:접속하는 DB의 IP를 지정 sid :
..접속하는 DB의 sid
..JDBC Driver
..Class
..oracle.jdbc.driver.OracleDriver ..DB에 접속하기 위해 사용할 JDBC
..드라이버명
..User Name ..DB user name ..DB에 접속하기 위한 User Name
..Password ..DB password
..DB에 접속하기 위한 Password
..Max. Active
..Connections
..10 ..동시에 서비스할 수 있는 최대 활성화
.. 커넥션의 수
..Max. Idle
..Connections
..5 ..최대 유휴 커넥션의 수
..Max. Wait for
..Connection
..1000 ..예외가 발생하여 커넥션을 해제할
..떄까지 최대로 기다리는 시간으로
..1/1000 초 단위
..Validation Query
..select * from tab ..반드시 입력해야 하며 Tomcat
..엔진에서 DB에 접속이 가능한지를
..자체적으로 확인하기 위한 Query

*. Save > Commit Save
*. %Tomcat%\conf\Catalina\localhost\jdbc.xml 파일 열기
*. jdbc.xml 파일에서 <Context> 태그 부분을 찾아서 <ResourceParams> 태그 중 name 속성의 값이 "jdbc/myoracle"인 부분 아래에 보면 이미 작성한 DataSource Properties 가 <parameter> </parameter> 태그 내에 정의 되어 있을 것이다.
*. <ResourceParams>와 </ResourceParams> 태그 사이에 다음 내용을 추가

<parameter>
  <name>removeAbandoned</name>
  <value>true</value>
</parameter>
<parameter>
  <name>removeAbandonedTimeout</name>
  <name>10</value>
</parameter>
  <name>logAbandoned</name>
  <value>true</balue>
</parameter>

* 추가되는 내용의 의미
  Revmoe Abandoned : 사용할 수 있는 커넥션이 부족해진다면 DBCP(Database Connection Pool)는 버려진 커넥션을 찾아 복구하고 재생. 디폴트는 false
  removeAbandonedTimeout : 커넥션이 버려졌다고 간주되기 전에 사용되지 않은 시간(초)를 설정하기 위해 사용. 버러젼 커넥션을 제거하는데 기본적으로 정해진 타임아웃 시가은 300초
  logAbandoned : 만일 커넥션 자원을 낭비한 코드 위치의 로그를 남길 수 있음. 기본은 false

* Tomcat 엔진 Restart



4. Tomcat 엔진에서 올바르게 JDBC 드라이버를 인식하는지 테스트 하기 위한 예제 (JSP)

<%@ page contentType="text/html;charset=euc-kr"
 import = "java.sql.*" %>
 
<%
 Connection con = null;
 Statement stmt = null;
 ResultSet rs = null;
 
 try{
  Class.forName("oracle.jdbc.driver.OracleDriver");
  con = DriverManger.getconnection(
    "jdbc:oracle:thin:@127.0.0.1:1521:ora9",
    "jdbc00", "jdbc00");
  stmt = con.createStatement();
  String query = "select tname from tab";
  rs = stmt.executeQuery(query);
  out.println("<h1>소유한 테이블은 다음과 같습니다.</h1>");
  out.println("<hr><br>");
  while(rs.next()){
   String result = rs.getString(1);
   out.println(result + "<br>");
  }
  rs.close();
  stmt.close();
  con.close();
 } catch(ClassNotFoundException e){
  System.out.println("JDBC 드라이버 로드 실패!");
  out.println("서버 장애가 발생하였습니다.");
 } catch(CSQLException e){
  System.out.println("DB using fail!");
  e.printStackTrace();
  out.println("서버 장애가 발생하였습니다.");
 } finally {
  try{
   if(rs != null) rs.close();
   if(stmt != null) stmt.close();
   if(con != null) con.close();
  }
  catch(SQLException e) { }
 }
%>

5. DataSource를 이용하여 oracle 데이터베이스 계정 내의 테이블 이름 조회하는 예제

oracledatasource.jsp

01  <%@ page contentType="text/html; charset=euc-kr" %>
02  <%@ page import =
03  "javax.naming.*,javax.sql.*,java.sql.*" %>
04  <html>
05   <head>
06    <title>
07     DataSource Test
08    </title>
09   </head>
10   <body>
11    <h3>
12     DataSource 를 이용하여 오라클 데이터베이스의
13     <br>    
14     테이블 이름을 조회하는 test 화면 입니다.
15    </h3>
16    <BR>
17    <hr>
18    <%
19    try{
20     Context initContext = new InitialContext();
21     if(initContext == null )
22     throw new Exception("Boom - No Context");
23     Context envContext  =
24     (Context)initContext.lookup("java:/comp/env");
25     DataSource ds =
26     (DataSource)envContext.lookup("jdbc/myoracle");
27     Connection conn = ds.getConnection();
28     out.println
29     ("DataSource 를 통하여 데이터베이스에 "
30     + "연결하였습니다.<BR>");
31     String queryStr="SELECT * FROM tab";
32     PreparedStatement pstmt =
33     conn.prepareStatement(queryStr);
34     ResultSet rs = pstmt.executeQuery();
35     out.println
36     ("<h5>테이블 조회 결과입니다<BR><BR></h5>");
37     while(rs.next()){
38      System.out.println("rs.next()");
39      out.println(rs.getString(1)+"<BR>");
40     }
41     rs.close();
42     pstmt.close();
43     conn.close();
44    }catch(Exception e) {
45     out.println("<BR>" + e.getMessage());
46     e.printStackTrace();
47    } finally {
try{
if(rs != null) rs.close();
if(ps != null) ps.close();  
if(con != null) con.close();
}catch(Exception e){}    
}
48    %>
49   </body>
50  </html> 

6. login.html

* 웹브라우저에서 사용자가 로그인 정보를 입력할 수 있는 화면
* html의 <form> 태그를 사용하여 id, password 두 가지의 로그인 정볼르 입력받을 수 있도록 구성하여 입력받은 정보를 login.jsp 로 전달
* %Tomcat%\Webapps\jdbc 디렉토리에 저장

login.html

01  <html>
02   <head>
03    <title>
04    회원 로그인
05    </title>
06   </head>
07  
08   <body>
09    <h1> 회원 리스트를 조회하려면
10    로그인 정보를 입력하세요. </h1>
11    <br>
12    <hr>
13    <br>
14    <h3>
15    <form action="/jdbc/login.jsp" method=post>
16     ID&nbsp;&nbsp;&nbsp;
17     <input type=text name=id size=10>
18     <br>
19     암호 <input type=password name=password size=10>
20     <br>
21     <!-- 이름 <input type=text name=name siez=20>
22     <br>-->
23     <input type=submit value=로그인>
24     <input type=reset value=입력취소>
25    </form>
26    </h3>
27    <br>
28    <hr>
29   </body>
30  </html> 

6. login.jsp
* login.html 에서 입력받은 사용자 로그인 정보를 전달받아서 이 정보들을 MemberDAO 객체로 전송
* %Tomcat%\webapps\jdbc 디렉토리에 저장

login.jsp

01  <%@ page contentType="text/html;charset=euc-kr" %>
02  <%@ page import="vo.*,java.util.Vector" %>
03  <jsp:useBean id="member" class="dao.MemberDAO" />
04  <%
05   ListVO memberList = null;
06   String result = "";
07   boolean isEmptyFlag = false;
08  
09   String id = request.getParameter("id");
10   String password = request.getParameter("password"); 
11  
12   switch(member.login(id, password)){
13   case 1:
14    result =
15    "입력하신 비밀 번호가 틀립니다.<br>"
16    + "확인하고 다시 입력하세요<br>";
17    isEmptyFlag = true;
18    break;
19   case 2:
20    result =
21    "회원이 아니시군요.<br>"
22    + "입력하신 id 를 다시 확인하시거나 <br>"
23    + "회원이 아니라면 회원가입을 먼저 하세요.<br>";
24    isEmptyFlag = true;
25    break;
26   default:
27    memberList = member.listMember();
28    if(memberList.getTotal()==0 ||
29    memberList.getList().size()==0){
30     isEmptyFlag=true;
31    }
32   }
33  %>
34  
35  <html>
36   <head>
37   <title>
38   회원 리스트 보기
39   </title>
40   </head>
41  
42   <body>
43   <% if(isEmptyFlag){ 
44   %>
45    <h1>
46    <%=result%>
47    </h1>           
48    <br><br>
49   <% } else {
50   %>
51    <h1> 회원 리스트는 다음과 같습니다.<br></h1>
52    <table border = 3>
53    <tr>
54    <th  align=center><h3>회원 ID</h3></th>
55    <th  align=center><h3>회원 이름</h3></th>
56    </tr>
57   <%       
58    //List 를 포함하기 위한 Vector
59    Vector tempList=memberList.getList();
60    for(int i = 0; i < tempList.size();i++){
61     DetailVO tempVO=(DetailVO)tempList.elementAt(i);
62   %>
63    <tr>
64    <td align=center><h4><%=tempVO.getId()%></h4></td>
65    <td align=center><h4><%=tempVO.getName()%></h4></td>
66    </tr>
67   <%
68    }
69   }
70   %>
71    </table>
72   </body>
73  </html> 

7. DetailVO.java

DetailVO.java

01  package vo;
02  
03  public class DetailVO {
04   /**
05   * 회원 id
06   */
07   private String id;
08  
09   /**
10   * 회원 암호
11   */
12   private String password;
13  
14   /**
15   * 회원 이름
16   */
17   private String name;
18  
19   /**
20   * 기본 Constructor
21   */
22   public DetailVO(){}
23  
24   /**
25   * Constructor
26   * @param  id 조회한 회원 id
27   * @param  password 조회한 회원 password
28   * @param  name 조회한 회원 이름
29   */
30   public DetailVO(String id, String password, String name){
31    this.id = id;
32    this.password = password;
33    this.name = name;
34   }
35  
36   /**
37   * 회원 id Getter Method
38   * @return String 조회한  회원 id
39   */
40   public String getId(){
41    return id;
42   }
43  
44   /**
45   * 회원 id Setter Method
46   * @param String 입력한 회원 id
47   */
48   public void setId(String id){
49    this.id = id;
50   }
51  
52   /**
53   * 회원 id Getter Method
54   * @return String 조회한  회원 password
55   */
56   public String getPassword(){
57    return password;
58   }
59  
60   /**
61   * 회원 id Setter Method
62   * @param String 조회한  회원 password
63   */
64   public void setPassword(String password){
65    this.password = password;
66   }
67  
68   /**
69   * 회원 name Getter Method
70   * @return String 조회한  회원 이름
71   */    
72   public String getName(){
73    return name;
74   }
75  
76   /**
77   * 회원 name Setter Method
78   * @param String 조회한  회원 이름
79   */
80   public void setName(String name){
81    this.name = name;
82   }
83  } 

7. ListVO.java

ListVO.java

01  package vo;
02  
03  import java.util.Vector;
04  
05  public class ListVO {
06   /**
07    * 조회된 회원 리스트
08    */
09   private Vector list;
10  
11   /**
12    * 총 회원 수
13    */
14   private long total;
15   
16   /**
17    * 기본 Constructor
18    */
19   public ListVO(){}
20  
21   /**
22    * 조회된 회원 리스트 Getter Method
23    * @return Vector 조회된 회원 리스트
24    */
25   public Vector getList(){
26       return list;
27   }
28  
29   /**
30    * 조회된 회원 리스트 Setter Method
31    * @param Vector 조회된 회원 리스트
32    */
33   public void setList(Vector list){
34       this.list = list;
35   }
36  
37   /**
38    * 총 회원수 Getter Method
39    * @return long 총 회원수
40    */
41   public long getTotal(){
42       return total; 
43   }
44  
45   /**
46    * 총 회원수 Setter Method
47    * @param long 총 회원수
48    */
49   public void setTotal(long total){
50       this.total = total; 
51   }
52  } 

8. MemberDAO.java

MemberDAO.java
 
01  package dao;
02  
03  import java.util.Vector;
04  import java.sql.*;
05  import javax.naming.*;
06  import javax.sql.*;
07  import vo.*;
08  
09  public class MemberDAO {
10  
11   /**
12   * 총 게시물 갯수를 얻는 Query
13   */
14   private static String stGET_TOTAL_NUM =
15   "SELECT COUNT(*) FROM MEMBER";
16  
17   /**
18   * 게시물 리스트를 얻는 Query
19   */
20   private static String stLIST_MEMBER =
21   "SELECT * FROM MEMBER";
22  
23   /**
24   *  비밀번호 확인 Query
25   */
26   private static String stCHECK_LOGIN =
27   "SELECT PASSWORD FROM MEMBER WHERE ID = ?";
28  
29   /**
30   * DataSource 객체 변수 선언
31   */
32   DataSource ds = null;
33  
34   /**
35   * 기본 Constructor
36   */
37   public MemberDAO()throws Exception {
38    Context initContext = new InitialContext();
39    Context envContext  =
40    (Context)initContext.lookup("java:/comp/env");
41    ds =(DataSource)envContext.lookup("jdbc/myoracle"); 
42   }
43  
44   public ListVO listMember() throws Exception {
45    ListVO retVO = new ListVO();
46    Statement stmt = null;
47    PreparedStatement pstmt = null;
48    ResultSet rs = null;
49    try {
50     Connection conn = ds.getConnection();
51     stmt = conn.createStatement();
52    
53     rs = stmt.executeQuery(stGET_TOTAL_NUM);
54     long total = 0;
55     if(rs.next()){
56      total = rs.getLong(1);
57      retVO.setTotal(total);
58     }
59    
60     pstmt = conn.prepareStatement(stLIST_MEMBER);
61     rs = pstmt.executeQuery();
62     Vector list = new Vector();
63     while(rs.next()){
64      DetailVO tempVO = new DetailVO
65      (rs.getString("id"),
66      rs.getString("password"),
67      rs.getString("name"));
68      list.addElement(tempVO);
69     }
70     retVO.setList(list);
71     rs.close();
72     stmt.close();
73     pstmt.close();
74     conn.close();
75    }catch (Exception e){
76     e.printStackTrace();
77     throw e;
78    }
79    return retVO;
80   }
81  
82   public int login(String id, String inputPass)
83   throws Exception {
84    PreparedStatement pstmt = null;
85    ResultSet rs = null;
86    int result = 0;
87    try {
88     Connection conn = ds.getConnection();
89     pstmt = conn.prepareStatement(stCHECK_LOGIN);
90     pstmt.setString(1,id);
91    
92     rs = pstmt.executeQuery();
93     if(rs.next()){
94      String dbPass = rs.getString(1); 
95      if(dbPass.equals(inputPass)){
96       result = 0;
97      }else {
98       result = 1;
99      }
100     }else {
101      result = 2;
102     } 
103     rs.close();
104     pstmt.close();
105     conn.close();
106    }catch (Exception e){
107     e.printStackTrace(); 
108     throw e;
109    }
110    return result;
111   }
112  }