반응형
실습을 위한 데이터베이스 테이블 생성
1
2
3
4
5
6
7
8
9
10
11
12
13
create table "TEMPMEMBER" (
    "ID"            varchar2(20) not null,
    "PASSWORD"         varchar2(20),
    "NAME"           varchar2(20),
    "MEM_NUM1"       varchar2(6),
    "MEM_NUM2"        varchar2(7),
    "E_MAIL"         varchar2(30),
    "PHONE"          varchar2(30),
    "ZIPCODE"        varchar2(7),
    "ADDRESS"        varchar2(60),
    "JOB"            varchar2(30),
    constraint  "TEMPMEMBER_PK" primary key ("ID")
);
cs

 

테이블이 생성되면 insert 문을 사용하여 데이터를 임의로 몇 개 넣어 놓는다.

1
2
3
4
5
6
7
8
insert into TEMPMEMBER values(
    'aaaa', '1111', '홍길동', '987654', '7654321', 
    'hong@naver.com', '02-tiger', '100-100', '서울', '프로그래머'
);
insert into TEMPMEMBER values(
    'bbbb', '2222', '이순신', '123123', '456456', 
    'lee@doum.net', '032-1212', '200-200', '부산', 'DBA'
);
cs

 

JAVA와 DB를 연결하기 위해 데이터베이스 드라이버를 Eclipse에 추가해준다.
 Eclipse에 드라이버 파일 추가


 Build Path에 해당 드라이버 추가하여 프로젝트에 적용

 

 

준비되었으면 예제파일 작성

 /WebContent/jsp_jdbc/usingJDBC.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="java.sql.*" %>
<%
    Class.forName("oracle.jdbc.driver.OracleDriver");
    Connection conn = null;
    Statement stmt = null;
    ResultSet rs = null;
    String     id = "",
            password = "",
            name = "",
            mem_num1 = "",
            mem_num2 = "",
            e_mail = "",
            phone = "",
            zipcode = "",
            address = "",
            job = "";
    int counter = 0;
    try{
        conn = DriverManager.getConnection(
                "jdbc:oracle:thin:@localhost:1521:xe""scott""tiger");
        stmt = conn.createStatement();
        rs = stmt.executeQuery("select * from TEMPMEMBER");
%>
<html>
<head>
<title>JSP에서 데이터베이스 연동하기</title>
</head>
<body bgcolor="#FFFFCC">
<h2>JSP 스크립틀릿에서 데이터베이스를 연동하는 예제</h2><br><br>
<h3>회원정보</h3>
    <table bordercolor="#0000FF" border="1">
        <tr>
            <td><strong> ID </strong></td>
            <td><strong> PASSWORD </strong></td>
            <td><strong> NAME </strong>
            <td><strong> MEM_NUM1 </strong></td>
            <td><strong> MEM_NUM2 </strong></td>
            <td><strong> E_MAIL </strong></td>
            <td><strong> PHONE </strong></td>
            <td><strong> ZIPCODE/ADDRESS </strong></td>
            <td><strong> JOB </strong></td>
        </tr>
<%
        if(rs!=null){
            while(rs.next()){
                id = rs.getString("id");
                password = rs.getString("password");
                name = rs.getString("name");
                mem_num1 = rs.getString("mem_num1");
                mem_num2 = rs.getString("mem_num2");
                e_mail = rs.getString("e_mail");
                phone = rs.getString("phone");
                zipcode = rs.getString("zipcode");
                address = rs.getString("address");
                job = rs.getString("job");
%>
        <tr>
            <td><%= id %></td>
            <td><%= password %></td>
            <td><%= mem_num1 %></td>
            <td><%= mem_num2 %></td>
            <td><%= e_mail %></td>
            <td><%= phone %></td>
            <td><%= zipcode %></td>
            <td><%= address %></td>
            <td><%= job %></td>
<%
                counter++;
            }//end while
        }//end if
%>
        </tr>
    </table><br><br>
total records : <%= counter %>
<%
    }catch(SQLException e){
        System.out.println("sql exception");
        e.printStackTrace();
    }catch(Exception e){
        System.out.println("exception");
        e.printStackTrace();
    }finally{
        if(rs != null){
            try{ rs.close(); } catch(SQLException e){}
        }
        if(stmt != null){
            try{ stmt.close(); } catch(SQLException e){}
        }
        if(conn != null){
            try{ conn.close(); } catch(SQLException e){}
        }
    }
%>
</body>
</html>
cs

 

 

실행결과

 

 

위와 같이 DB를 연동하면 동작은 잘 된다. 하지만 이런 방법으로 DB와 연결을 할 경우 문제점이라고 할 수 있는 것이 있다. 그것은 JSP페이지를 요청할 때마다 Connection 객체를 새로 생성한다는 것이다. 일단 문제점을 예를 들어 말하자면 클라이언트가 부산에 있고 JSP를 처리하는 서버가 서울에 있다. 그리고 DB서버가 미국에 있다면? 이 때 클라이언트의 요청마다 Connection이 만들어 지도록 한다면 분명 네트워크상에서 Delay 라든지 많은 요청이 있을 경우 처리하는 속도문제로 끊기는 일 등이 일어날 수 있을 것이다.

 

 이를 보완하기 위해 Connection Pool이라는 기능을 만들어 미리 Connection 객체를 생성 해놓고 요청이 있을 때 놀고있는 커넥션객체를 사용하여 데이터베이스 요청을 처리하고 응답을 하는 방법을 사용한다.

 

 

 

 커넥션풀(Connection Pool)

- 데이터베이스와 접속한 상태로 대기하고 있는 커넥션 객체를 담아놓은 그릇

 

 실제로는 라이브러리 형태로 제공되는 커넥션풀 객체를 활용하면 된다.

여기서는 먼저 개념 이해를 위해 직접 ConnectionPool 클래스를 작성하여 동작을 구현해보도록 한다.

 

Connection Pool 만들기
    Connection을 저장 할 수 있는 두 개의 컬렉션을 생성한다.(여기서는 Vecrot사용)
    사용 전 Connection 객체를 담는 Freed(Vector)
        ConnectionPool 클래스로 객체를 생성할 때 미리 Connection객체를 담아 둔다.
    사용 중 Connection 객체를 담는 Used(Vector)
        실제로 DBMS와 연결을 할 때 Freed에 있는 Connection객체를 가져와 담는다.

Used에 있는 Connection객체로 DB에 접속하여 요청을 처리한 후 사용을 다 하면 다시 Freed로 옮기는 방식으로 동작한다.

 

다음과 같이 ConnectionPool 클래스 생성

/src/jsp_jdbc/ConnectionPool.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package jsp_jdbc;
 
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
 
public class ConnectionPool {
    static{
        try{
            Class.forName("oracle.jdbc.driver.OracleDriver");
            
        }catch(ClassNotFoundException e){
            e.printStackTrace();
        }        
    }
    private ArrayList<Connection> freed;     //사용 전 Connection
    private ArrayList<Connection> used;     //사용 중 Connection
    private String url = "jdbc:oracle:thin:@localhost:1521:xe";
    private String id = "scott";            //DB계정의 ID
    private String password = "tiger";    //DB계정의 Password
    private int initCons = 10;        //초기 Connection 수
    private int maxCons = 20;        //최대 Connection 수
    private int numCons = 0;        //전체 Connection 수
    private static ConnectionPool cp;
    public static ConnectionPool getInstance(){
        try{
            if(cp == null){
                synchronized(ConnectionPool.class){
                    cp = new ConnectionPool();
                }
            }
        }
        catch(SQLException e){
            e.printStackTrace();
        }
        return cp;
    }
    private ConnectionPool() throws SQLException{
        /*
         * 초기 Connection개수를 각각의 ArrayList에 저장 할 수 있도록
         * 초기 Connection 수 만큼 생성
         */
        freed = new ArrayList<Connection>(initCons);
        used = new ArrayList<Connection>(initCons);
        //initCons 의 수만큼 Connection생성
        while(numCons < initCons){
            addConnection();
        }
    }
    private void addConnection() throws SQLException{
        freed.add(getNewConnection());
    }
    private Connection getNewConnection()throws SQLException{
        Connection conn = null;
        try{
            conn = DriverManager.getConnection(url, id, password);
        }catch(SQLException e){
            e.printStackTrace();
        }
        System.out.println("About to connect to " + conn);
        numCons++;
        return conn;
    }
    //요청이 왔을 때 freed에 있는 Connection을 used로 옮기는 기능
    public synchronized Connection getConnection() throws SQLException{
        if(freed.isEmpty()){
            while(numCons < maxCons){
                addConnection();
            }
        }
        Connection _conn = freed.get(freed.size()-1);
        freed.remove(_conn);
        used.add(_conn);
        return _conn;
    }
    
    //요청 처리가 끝나면 used의 Connection객체를 freed로 옮기는 기능 
    public synchronized void releaseConnection(Connection _conn) throws SQLException{
        boolean flag = false;
        if(used.contains(_conn)){
            used.remove(_conn);
            numCons--;
            flag = true;
        }
        else{
            throw new SQLException("ConnectionPool에 없습니다. ");
        }
        try{
            if(flag){    freed.add(_conn); numCons++; }
            else{        _conn.close(); }
        }
        catch(SQLException e){
            try    {_conn.close();}
            catch(SQLException e1){e1.printStackTrace();}
        }
    }
    //모든 Connection 삭제
    public void closeAll(){
        //사용 중인 모든 Connection객체 삭제
        for(int i = 0; i < used.size(); i++){
            Connection _conn = used.get(i);
            used.remove(i--);
            try{
                _conn.close();
            }
            catch(SQLException e){
                try    {_conn.close();}
                catch(SQLException e1){e1.printStackTrace();}
            }
        }
        //사용 전인 모든 Connection객체 삭세
        for(int i = 0; i < freed.size(); i++){
            Connection _conn = freed.get(i);
            freed.remove(i--);
            try{
                _conn.close();
            }
            catch(SQLException e){
                try    {_conn.close();}
                catch(SQLException e1){e1.printStackTrace();}
            }
        }
    }
    public int getNumCons(){
        return numCons;
    }
}
cs

 

작성 후 위에서 만든 ConnectionPool클래스를 사용하여 동작되는지 확인
앞에서 만든 usingJDBC.jsp 를 복사하여

/WebContent/jsp_jdbc/usingConnectionPool.jsp 파일 생성

1.  수정할 부분

이 부분을 다음과 같이 수정


2. Class.forName부분 삭제

   3. ConnectionPool 생성

  


 
4. 다음 부분을

 
다음과 같이 수정


   5. 마지막 부분의 conn.close()부분을 다음과 같이 수정

커넥션을 닫는 것이 아니라 사용중이 아닌 상태의 컬렉션으로 이동하는 개념

수정을 완료 했으면 usingConnectionPool.jsp를 실행해 본다.


Connection 객체를 생성하고 요청에 응답한다.(Console에 출력된 Connection객체정보)
 


결과 웹 페이지

결과는 동일하지만 요청에 따른 Connection을 계속 생성하지 않기 때문에 훨씬 효율적이다.

위 코드를 분석해서 Connection Pool의 개념을 명확히 이해하도록 하자. 코드의 형태는 당연히 달라질 수 있다.

 

이번엔 JavaBeans를 적용하여 데이터 가져오기.
먼저 Tempmember에 대한 Value Object로 사용할 Beans를 만든다.

/src/jsp_jdbc/TempMemberVO.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package jsp_jdbc;
 
public class TempMemberVO {
    private String id;
    private String password;
    private String name;
    private String mem_num1;
    private String mem_num2;
    private String e_mail;
    private String phone;
    private String zipcode;
    private String address;
    private String job;
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getMem_num1() {
        return mem_num1;
    }
    public void setMem_num1(String mem_num1) {
        this.mem_num1 = mem_num1;
    }
    public String getMem_num2() {
        return mem_num2;
    }
    public void setMem_num2(String mem_num2) {
        this.mem_num2 = mem_num2;
    }
    public String getE_mail() {
        return e_mail;
    }
    public void setE_mail(String e_mail) {
        this.e_mail = e_mail;
    }
    public String getPhone() {
        return phone;
    }
    public void setPhone(String phone) {
        this.phone = phone;
    }
    public String getZipcode() {
        return zipcode;
    }
    public void setZipcode(String zipcode) {
        this.zipcode = zipcode;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    public String getJob() {
        return job;
    }
    public void setJob(String job) {
        this.job = job;
    }
    
}
cs

 

이어서 데이터베이스에 접속하여 데이터베이스 객체를 조작하는 DAO클래스 작성

/src/jsp_jdbc/TempMemberDAO.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package jsp_jdbc;
 
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Vector;
 
public class TempMemberDAO {
    private final String JDBC_DRIVER = "oracle.jdbc.driver.OracleDriver";
    private final String JDBC_URL = "jdbc:oracle:thin:@localhost:1521:xe";
    private final String ID = "scott";    //사용할 DB계정 ID
    private final String PW = "tiger";    //사용할 DB계정 password
    public TempMemberDAO(){
        try{
            Class.forName(JDBC_DRIVER);
        }catch(ClassNotFoundException e){
            System.out.println("드라이버 로딩 실패!");
            e.printStackTrace();
        }        
    }
    public Vector<TempMemberVO> getMemberList(){
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        Vector<TempMemberVO> memList = new Vector<TempMemberVO>();
        try{
            conn = DriverManager.getConnection(JDBC_URL, ID, PW);
            String query = "select * from TEMPMEMBER";
            stmt = conn.createStatement();
            rs = stmt.executeQuery(query);
            while(rs.next()){
                TempMemberVO tmp = new TempMemberVO();
                tmp.setId(rs.getString("id"));
                tmp.setPassword(rs.getString("password"));
                tmp.setName(rs.getString("name"));
                tmp.setMem_num1(rs.getString("mem_num1"));
                tmp.setMem_num2(rs.getString("mem_num2"));
                tmp.setE_mail(rs.getString("e_mail"));
                tmp.setPhone(rs.getString("phone"));
                tmp.setZipcode(rs.getString("zipcode"));
                tmp.setAddress(rs.getString("address"));
                tmp.setJob(rs.getString("job"));
                memList.add(tmp);
            }
        } catch(Exception e){
            System.out.println("Exception : " + e);
        } finally{
            if(rs != nulltry{rs.close();}catch(Exception e){}
            if(stmt != nulltry{stmt.close();}catch(Exception e){}
            if(conn != nulltry{conn.close();}catch(Exception e){}
        }
        return memList;
    }
}
 
cs

 

이제 위에서 만든 TempMemberVO와 jdbc를 사용하여 jsp에서 데이터를 출력해보기 위한 jsp코드를 작성한다.

javaBeans를 사용하는 방법으로 다음 코드 작성
/WebContent/jsp_jdbc/usingBeans.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="java.util.*, jsp_jdbc.*" %>
<html>
<head>
<title>JSP에서 데이터베이스 연동하기</title> 
</head>
<body bgcolor="#FFFFCC">
<h2>Beans를 사용한 데이터베이스 연동 예제</h2><br><br>
<h3>회원 정보</h3>
    <table bordercolor="#0000FF" border="1">
        <tr>
            <td><strong> ID </strong></td>
            <td><strong> PASSWORD </strong></td>
            <td><strong> NAME </strong>
            <td><strong> MEM_NUM1 </strong></td>
            <td><strong> MEM_NUM2 </strong></td>
            <td><strong> E_MAIL </strong></td>
            <td><strong> PHONE </strong></td>
            <td><strong> ZIPCODE/ADDRESS </strong></td>
            <td><strong> JOB </strong></td>
        </tr>
        <jsp:useBean id="dao" class="jsp_jdbc.TempMemberDAO" scope="page"/>
<%
    Vector<TempMemberVO> vlist = dao.getMemberList();
    int counter = vlist.size();
    for(int i = 0; i < vlist.size(); i++){
        TempMemberVO tmp = vlist.elementAt(i);
%>        
        <tr>
            <td><%= tmp.getId() %></td>
            <td><%= tmp.getName() %></td>
            <td><%= tmp.getPassword() %></td>
            <td><%= tmp.getMem_num1() %></td>
            <td><%= tmp.getMem_num2() %></td>
            <td><%= tmp.getE_mail() %></td>
            <td><%= tmp.getPhone() %></td>
            <td><%= tmp.getZipcode() %>/<%= tmp.getAddress() %></td>
            <td><%= tmp.getJob() %></td>
<%
    }
%>
        </tr>
        </table>
        <br><br>
        total records : <%= counter %>
</body>
</html>
cs


실행결과(역시 동일한 결과를 보여준다.)

 

JavaBeans와 ConnectionPool 적용하기
이제 위에서 만들어봤던 JavaBeans개념과 ConnectionPool을 모두 적용시켜본다.


1. TempMemberDAO 코드에서 아래와 같이 수정
 

 

2. 생성자 부분을 다음과 같이 수정한다.
 

 

3. 다음 부분을 수정한다.
 

 

4. 다음 부분을 수정한다.     


5. usingBeans.jsp 파일을 복사하여 usingConnectionBeans.jsp파일을 만들고 실행해본다.

실행결과

 

 

위 예제는 ConnectionPool을 직접 만들어서 적용한 것이다. 이번에는 WAS에서 제공해주는 ConnectionPool을 사용하여 적용시켜본다.

 

1. 라이브러리 파일 준비

Tomcat 설치 폴더에 lib폴더 목록 보면 tomcat-dbcp.jar파일이 있는데 이 파일이 커넥션풀 기능을 구현해 놓은 라이브러리 파일이다.

해당 파일을 다음과 같이 웹 프로젝트 폴더의 lib폴더에 복사한다.(중요!)

2. 라이브러리를 사용할 수 있도록 프로젝트의 설정파일 작성

Eclipse의 META-INF/context.xml파일을 다음과 같이 작성

/WebContent/META-INF/context.xml (없으면 생성)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="UTF-8"?>
<Context>
    <Resource name="jdbc/myOracle"
           auth="Container"
           driverClassName="oracle.jdbc.driver.OracleDriver"
           type="javax.sql.DataSource"
           url="jdbc:oracle:thin:@localhost:1521:xe"
           username="데이터베이스접속계정"
           password="데이터베이스접속계정비밀번호"
           initialSize="50"
           maxTotal="20"     
           maxIdle="10"
           maxWaitMillis="10000"    />
<!-- 
    initialSize
        : 최초 시점에 getConnection() 를 통해 커넥션 풀에 채워 넣을 커넥션 개수 (default = 0)
    maxTotal (1.x에서는 maxActive): 
        : 동시에 사용할 수 있는 최대 커넥션 개수 (default = 8)
    maxIdle
        : Connection Pool에 반납할 때 최대로 유지될 수 있는 커넥션 개수 (default = 8)
    minIdle 
        : 최소한으로 유지할 커넥션 개수 (default = 0)
    maxWaitMillis (1.x에서는 maxWait) 
        : pool이 고갈되었을 경우 최대 대기 시간 (ms단위, default = -1 = 무한정)
-->
</Context>
cs

 

3. Eclipse의 WEB-INF/web.xml파일을 다음과 같이 작성
/WebContent/WEB-INF/web.xml파일 수정 – 톰캣에서 Resource정보를 통해서 DB를 사용

1
2
3
4
5
6
<resource-ref>
    <description>ConnectionPool</description>
    <res-ref-name>jdbc/myOracle</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
</resource-ref>
cs

 

4. 앞으로 JSP작성 또는 JAVA작성 시 파일 내에서 다음과 같이 사용하면 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import java.sql.Connection;
 
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
 
 
public class DAO {
public DAO(){
    try{
        Context init = (Context) new InitialContext();
        DataSource ds = (DataSource)init.lookup("java:comp/env/jdbc/myOracle");
        conn = ds.getConnection();
    } catch(Exception e){
        System.out.println("Exception : " + e);
    } finally{    
        if(conn != nulltry{conn.close();}catch(Exception e){}
    }
    
    /* Connection객체가 필요한 곳에서 호출하여 객체를 얻어가도록 한다.*/
    public Connection getConnection(){
        return ds.getConnection();
    }
}
 
cs

 

5. 앞의 usingConnectionBeans.jsp를 복사하여 usingConnectionBeans_dbcp.jsp파일을 만들고 위에서 설정한 WAS의 ConnectionPool을 사용하도록 코드를 수정하여 실행해보자. 


이제 JSP에서 커넥션풀을 이용하여 데이터베이스를 사용할 수 있다.

 

반응형

+ Recent posts