19.05.05 커넥션풀을 사용한 데이터베이스 연결 (동영상)

Back-End/JSP 2019. 5. 5. 20:32
728x90
반응형

-커넥션 풀 (DBCP) 사용 이유-

 

JDBC를 통하여 DB에 연결하기 위해서는 드라이버를 로드하고 커넥션 객체를 받아와야한다.

JDBC를 사용하면 사용자가 요청을 할 때마다 매번 드라이버를 로드하고 커넥션 객체를 생성하여

연결하고 종료하기 때문에 매우 비효율적이다.

이런 문제를 해결하기 위해서 커넥션풀(DBCP)를 사용한다. (드라이버를 미리 만들어 놓는다.)

 

 

 

-커넥션풀(DBCP)-

 

웹 컨테이너(아파치톰캣)가 실행되면서 커넥션 객체를 미리 풀에 생성해 둡니다.

DB와 연결된 커넥션을 미리 생성해서 풀 속에 저장해 두고 있다가 필요할 때에 가져다 쓰고 반환한다.

미리 생성해두기 때문에 데이터베이스에 부하를 줄이고 유동적으로 연결을 관리 할 수 있다.

 

 

커넥션풀 사용방법

 

  

  server -> server.xml (소스파일 수정)

  <Resource name = "jdbc/pool" auth="Container" type="javax.sql.DataSource"   
         driverClassName="oracle.jdbc.driver.OracleDriver" loginTimeout="10" maxWait="5000"
         username="system" password = "123456" url = "jdbc:oracle:thin:@localhost:1521:xe"/>
        </Context>

  DAO 클래스에 있던 데이터베이스와 연결하는 코드를 써주면 된다.

 


 

 

-예제 및 출력 결과-

 

server.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
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
<?xml version="1.0" encoding="UTF-8"?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at
      http://www.apache.org/licenses/LICENSE-2.0
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
--><!-- Note:  A "Server" is not itself a "Container", so you may not
     define subcomponents such as "Valves" at this level.
     Documentation at /docs/config/server.html
 --><Server port="8005" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener"/>
  <!-- Security listener. Documentation at /docs/config/listeners.html
  <Listener className="org.apache.catalina.security.SecurityListener" />
  -->
  <!--APR library loader. Documentation at /docs/apr.html -->
  <Listener SSLEngine="on" className="org.apache.catalina.core.AprLifecycleListener"/>
  <!-- Prevent memory leaks due to use of particular java/javax APIs-->
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener"/>
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/>
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener"/>
 
  <!-- Global JNDI resources
       Documentation at /docs/jndi-resources-howto.html
  -->
  <GlobalNamingResources>
    <!-- Editable user database that can also be used by
         UserDatabaseRealm to authenticate users
    -->
    <Resource auth="Container" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" name="UserDatabase" pathname="conf/tomcat-users.xml" type="org.apache.catalina.UserDatabase"/>
  </GlobalNamingResources>
 
  <!-- A "Service" is a collection of one or more "Connectors" that share
       a single "Container" Note:  A "Service" is not itself a "Container",
       so you may not define subcomponents such as "Valves" at this level.
       Documentation at /docs/config/service.html
   -->
  <Service name="Catalina">
 
    <!--The connectors can use a shared executor, you can define one or more named thread pools-->
    <!--
    <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
        maxThreads="150" minSpareThreads="4"/>
    -->
 
 
    <!-- A "Connector" represents an endpoint by which requests are received
         and responses are returned. Documentation at :
         Java HTTP Connector: /docs/config/http.html
         Java AJP  Connector: /docs/config/ajp.html
         APR (HTTP/AJP) Connector: /docs/apr.html
         Define a non-SSL/TLS HTTP/1.1 Connector on port 80
    -->
    <Connector URIEncoding="EUC-KR" connectionTimeout="20000" port="80" protocol="HTTP/1.1" redirectPort="8443"/>
    <!-- A "Connector" using the shared thread pool-->
    <!--
    <Connector executor="tomcatThreadPool"
               port="80" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    -->
    <!-- Define a SSL/TLS HTTP/1.1 Connector on port 8443
         This connector uses the NIO implementation. The default
         SSLImplementation will depend on the presence of the APR/native
         library and the useOpenSSL attribute of the
         AprLifecycleListener.
         Either JSSE or OpenSSL style configuration may be used regardless of
         the SSLImplementation selected. JSSE style configuration is used below.
    -->
    <!--
    <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
               maxThreads="150" SSLEnabled="true">
        <SSLHostConfig>
            <Certificate certificateKeystoreFile="conf/localhost-rsa.jks"
                         type="RSA" />
        </SSLHostConfig>
    </Connector>
    -->
    <!-- Define a SSL/TLS HTTP/1.1 Connector on port 8443 with HTTP/2
         This connector uses the APR/native implementation which always uses
         OpenSSL for TLS.
         Either JSSE or OpenSSL style configuration may be used. OpenSSL style
         configuration is used below.
    -->
    <!--
    <Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol"
               maxThreads="150" SSLEnabled="true" >
        <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
        <SSLHostConfig>
            <Certificate certificateKeyFile="conf/localhost-rsa-key.pem"
                         certificateFile="conf/localhost-rsa-cert.pem"
                         certificateChainFile="conf/localhost-rsa-chain.pem"
                         type="RSA" />
        </SSLHostConfig>
    </Connector>
    -->
 
    <!-- Define an AJP 1.3 Connector on port 8009 -->
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443"/>
 
 
    <!-- An Engine represents the entry point (within Catalina) that processes
         every request.  The Engine implementation for Tomcat stand alone
         analyzes the HTTP headers included with the request, and passes them
         on to the appropriate Host (virtual host).
         Documentation at /docs/config/engine.html -->
 
    <!-- You should set jvmRoute to support load-balancing via AJP ie :
    <Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">
    -->
    <Engine defaultHost="localhost" name="Catalina">
 
      <!--For clustering, please take a look at documentation at:
          /docs/cluster-howto.html  (simple how to)
          /docs/config/cluster.html (reference documentation) -->
      <!--
      <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
      -->
 
      <!-- Use the LockOutRealm to prevent attempts to guess user passwords
           via a brute-force attack -->
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <!-- This Realm uses the UserDatabase configured in the global JNDI
             resources under the key "UserDatabase".  Any edits
             that are performed against this UserDatabase are immediately
             available for use by the Realm.  -->
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
      </Realm>
 
      <Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true">
 
        <!-- SingleSignOn valve, share authentication between web applications
             Documentation at: /docs/config/valve.html -->
        <!--
        <Valve className="org.apache.catalina.authenticator.SingleSignOn" />
        -->
 
        <!-- Access log processes all example.
             Documentation at: /docs/config/valve.html
             Note: The pattern used is equivalent to using pattern="common" -->
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" pattern="%h %l %u %t &quot;%r&quot; %s %b" prefix="localhost_access_log" suffix=".txt"/>
 
      <Context docBase="myapp" path="/myapp" reloadable="true" source="org.eclipse.jst.jee.server:myapp"/>
      <Context docBase="chap6-jsp" path="/chap6-jsp" reloadable="true" source="org.eclipse.jst.jee.server:chap6-jsp"/>
      <Context docBase="ch11" path="/ch11" reloadable="true" source="org.eclipse.jst.jee.server:ch11">
          <Resource name = "jdbc/pool" auth="Container" type="javax.sql.DataSource"            
          driverClassName="oracle.jdbc.driver.OracleDriver" loginTimeout="10" maxWait="5000"
          username="system" password = "123456" url = "jdbc:oracle:thin:@localhost:1521:xe"/>
      
      </Context> //커넥션 풀을 사용하기 위해 데이터베이스와 연결하는 코드를 추가 (DAO 클래스에 있던 것처럼)
      </Host>
    </Engine>
  </Service>
</Server>
cs

 

 

MemberDAO.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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
package ch11;
 
import java.sql.*//SQL 패키지인지 반드시 확인
import java.util.Vector;
 
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
//*을 쓰면 sql에 있는 패키지를 모두 가져오기 때문에 따로 안써도 된다.
 
//오라클 데이터 베이스에 연결하고 SELECT, INSERT, UPDATE, DELETE 작업을 실행해주는 클래스입니다.
public class MemberDAO {
 
    // 아이디,비밀번호 사용해서 연결하는 부분은 반복적으로 계속 사용하므로 메소드로 만드는 것이 좋다.
 
    // 오라클에 접속하는 소스를 작성
    /*
     * String id = "system"; String pass = "123456"; String url =
     * "jdbc:oracle:thin:@localhost:1521:XE"; // 접속 URL
     */ 
    Connection con; // 데이터베이스에 접근할수 있도록 설정
    PreparedStatement pstmt; // 데이터베이스에서 쿼리를 실행시켜주는 객체
    ResultSet rs; // 데이터베이스의 테이블의 결과(SELECT, INSERT, UPDATE, DELETE 등)
                    // 데이터베이스의 테이블의 결과를 리턴받아 자바에 저장해주는 객체
 
    // 데이터베이스에 접근할 수 있도록 도와주는 메소드
 
    public void getCon() {
        
        //커넥션 풀을 이용하여 데이터 베이스에 접근
        try 
        {
            //외부에서 데이터를 읽어들어야 하기 때문에 Context 객체 생성
            Context initctx =  new InitialContext();
            
            //톰캣 서버에 정보를 담아놓은 곳으로 이동
            Context envctx = (Context) initctx.lookup("java:comp/env"); //오브젝트 타입이기때문에 Context타입으로 타입변환
            
            //데이터 소스 객체를 선언
            DataSource ds = (DataSource) envctx.lookup("jdbc/pool");//오브젝트 타입이기때문에 Context타입으로 타입변환
            
            //데이터 소스를 기준으로 커넥션을 연결
            con = ds.getConnection();
            
        } 
        catch (Exception e) 
        {
            e.printStackTrace();
        }
  
        
        /*
         * try { // 1.해당 데이터베이스를 사용한다고 선언 (클래스를 등록 = 오라클을 사용)
         * Class.forName("oracle.jdbc.driver.OracleDriver"); // 2. 해당 데이터 베이스에 접속 con =
         * DriverManager.getConnection(url, id, pass); // con 앞에 Connection을 쓰면 메소드의
         * 지역변수에 저장이 되기때문에 쓰지 않는다 } catch (Exception e) {
         * 
         * }
         */
    }
 
    // 데이터베이스에 한사람의 회원 정보를 저장해주는 메소드
    public void insertMember(MemberBean mbean) {
        try {
            getCon();
            // 3. 접속후 쿼리준비하여 쿼리를 사용하도록 설정
            String sql = "insert into member values(?,?,?,?,?,?,?,?)"// 8개의 값이 들어간다.
            // 쿼리를 사용하도록 설정
            PreparedStatement pstmt = con.prepareStatement(sql); // jsp 에서 쿼리를 사용하도록 설정
            // ?에 맞게 데이터를 맵핑
            pstmt.setString(1, mbean.getId()); // SQL의 insert to values에 넣을 값들.
            pstmt.setString(2, mbean.getPass1());
            pstmt.setString(3, mbean.getEmail());
            pstmt.setString(4, mbean.getTel());
            pstmt.setString(5, mbean.getHobby());
            pstmt.setString(6, mbean.getJob());
            pstmt.setString(7, mbean.getAge());
            pstmt.setString(8, mbean.getInfo());
            // 4. 오라클에서 쿼리를 실행 하시오.
            pstmt.executeUpdate(); // insert, update, delete 시 사용하는 메소드
 
            // 5. 자원 반납
            con.close();
 
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
    // 모든 회원의 정보를 리턴해주는 메소드 호출
    // 아까 벡터로 받았기 때문에 리턴타입을 Vector<MemberBean>로 사용한다.
 
    // 회원가입을 했을 때 자료는 bean클래스에 일단 저장하고 다시 벡터에 저장 (반복한다)
    public Vector<MemberBean> allSelectMember() {
        // 가변길이로 데이터를 저장
        Vector<MemberBean> v = new Vector<>();
 
        // 무조건 데이터 베이스는 예외처리를 해야된다.
        // 무조건 예외처리를 해야될때 (데이터베이스, 네트워크, 스레드, 입출력)
        try {
            // 커넥션 연결 (getCon() 메소드를 호출해서 데이터베이스와 연결)
            getCon();
            // 쿼리 준비
            String sql = "select * from member";
            // 쿼리를 실행시켜주는 객체 선언
            pstmt = con.prepareStatement(sql);
            // 쿼리를 실행 시킨 결과를 리턴해서(오라클 테이블의 검색된 결과를 자바객체에 저장)
            rs = pstmt.executeQuery(); // 데이터베이스의 쿼리를 실행한 데이터가 rs에 저장된다.
            // 반복문을 사용해서 rs에 저장된 데이터를 추출해놓아야 한다.
            while (rs.next()) // 저장된 데이터만큼 반복문 실행한다는 뜻
            {
                MemberBean bean = new MemberBean(); // 데이터베이스에서 멤버빈클래스로 데이터를 받아야 하기 때문에 객체 생성
                bean.setId(rs.getString(1)); // 컬럼으로 나뉘어진 데이터를 빈클래스에 저장, 계속 데이터를 넣어야 하기때문에 새로운 객체를 계속 만들어야함
                bean.setPass1(rs.getString(2));
                bean.setEmail(rs.getString(3));
                bean.setTel(rs.getString(4));
                bean.setHobby(rs.getString(5));
                bean.setJob(rs.getString(6));
                bean.setAge(rs.getString(7));
                bean.setInfo(rs.getString(8));
                // 패키징된 memberbean 클래스를 벡터에 저장
                v.add(bean); // 벡터에 0번지부터 순서대로 데이터가 저장
            }
            // 자원 반납
            con.close();
 
        } catch (Exception e) {
 
        }
 
        // 다 저장된 벡터를 리턴
        return v;
    }
 
    
    //한사람의 대한 정보를 리턴하는 메소드 작성
    public MemberBean oneSelectMember(String id) 
    {
        MemberBean bean = new MemberBean();
        try 
        
        {
            //커넥션 연결
            getCon();
            //쿼리 준비
            String sql = "select * from member where id=?";
            pstmt = con.prepareStatement(sql);
            //인덱스와 값을 매핑한다.
            pstmt.setString(1, id);
            //쿼리 실행
            rs = pstmt.executeQuery();
            if(rs.next()) {
                //레코드가 있다면
                bean.setId(rs.getString(1)); // 컬럼으로 나뉘어진 데이터를 빈클래스에 저장, 계속 데이터를 넣어야 하기때문에 새로운 객체를 계속 만들어야함
                bean.setPass1(rs.getString(2));
                bean.setEmail(rs.getString(3));
                bean.setTel(rs.getString(4));
                bean.setHobby(rs.getString(5));
                bean.setJob(rs.getString(6));
                bean.setAge(rs.getString(7));
                bean.setInfo(rs.getString(8));
            }
            con.close();
            
        }
        catch (Exception e)
        
        {
            e.printStackTrace();
        }
        //리턴
        return bean;
    }
    
    //한 회원의 패스워드 값을 리턴하는 메소드 작성
    public String getPass(String id) //스트링으로 리턴을 해야하기에 스트링 변수 선언
    {
        String pass = ""//초기값은 지역변수이기 때문에 값이 없이 시작
        try {
            getCon();
            //쿼리 준비
            String sql = "select pass1 from member where id=?";
            pstmt = con.prepareStatement(sql);
            //인덱스와 값을 매핑한다.
            pstmt.setString(1, id);
            //쿼리 실행
            rs = pstmt.executeQuery();
            if(rs.next()) 
            {
                pass=rs.getString(1); //패스워드 값이 저장된 컬럼인덱스
            }
            //자원 반납
            con.close();
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        //결과를 리턴
        return pass;
        
    }
    
    
    //한회원의 정보를 수정하는 메소드
    public void updateMember(MemberBean bean) 
    {
        getCon();
        try {
            //쿼리 준비
            String sql = "update member set email=?,tel=? where id=?"//아이디로 이메일과 전화번호를 식별한다.
            //쿼리 실행 객체 선언
            pstmt = con.prepareStatement(sql);
            //?에 값을 연결
            pstmt.setString(1, bean.getEmail());//각각 해당하는 값들을 빈클래스에서 받아온다.
            pstmt.setString(2, bean.getTel());
            pstmt.setString(3, bean.getId());
            
            pstmt.executeUpdate(); //result로 부터 받는값이 아니기 때문에 execute()는 사용불가.
            
            con.close();//자원반납
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
   
    //한 회원을 삭제하는 메소드 작성
    public void deleteMember(String id) 
    {
        getCon();
        try {
            //쿼리 준비
            String sql = "delete from member where id=?";
            //쿼리 실행 객체 선언
            pstmt = con.prepareStatement(sql);
            //?에 값을 연결
            pstmt.setString(1, id);//각각 해당하는 값들을 빈클래스에서 받아온다.
        
            
            pstmt.executeUpdate(); //result로 부터 받는값이 아니기 때문에 execute()는 사용불가.
            
            con.close();//자원반납
            
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
    
    
}
 
cs

 

 

728x90
반응형
: