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

Back-End/JSP 2019. 5. 5. 20:32

-커넥션 풀 (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

 

 

:

java, 이클립스, 톰캣 설치 사이트

Back-End 2019. 5. 5. 18:55

이클립스

https://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/2019-03/R/eclipse-jee-2019-03-R-win32-x86_64.zip&mirror_id=1142

 

 

java

https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

 

 

톰캣

https://tomcat.apache.org/download-80.cgi

:

19.05.05 Cookie & Session (책+동영상)

Back-End/JSP 2019. 5. 5. 13:12

 -쿠키란?-

 

서버측에서 사용자가 필요한 정보들를 담아서 "내 컴퓨터" 에 넘겨주는 것!

쿠키는 웹브라우저 자체의 쿠키 저장소에 저장.

 

(Response 객체에 쿠키값을 넘겨서 사용)

 

메소드 이름 

설명 

int getMaxAge( )

Cookie의 최대 지속시간을 초 단위로 지정합니다. -1일 경우 브라우저가 종료되는 쿠키를 만료

String getName( ) 

Cookie의 이름을 스트링 타입으로 반환 

String getValue( )

Cookie의 값을 스트링 타입으로 반환 

void setMaxAge(int expiry) 

Cookie의 만료시간을 초 단위로 설정합니다. 

void setValue(String newValue) 

Cookie에 새로운 값을 설정할 때 사용합니다. 

 

 

 

 

-예제 및 출력 결과-

 

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
<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>
 
    <%
        //사용자 컴퓨터의 쿠키 저장소로부터 쿠키값을 읽어들임. 몇개인지 모르기에 배열을 이용하여 쿠키값을 저장
        Cookie[] cookies = request.getCookies();
        String id = "";
 
        //쿠키값이 없을 수도 있기에 null 처리를 해줍니다.
        if (cookies != null) {
            for (int i = 0; i < cookies.length; i++//쿠키에 담긴값을 출력
            {
                if (cookies[i].getName().equals("id")) //쿠키에 담긴 값의 이름과  id가 같을때 실행
                {
                    id = cookies[i].getValue();
                    break//원하는 아이디를 찾았을때 멈춘다.
                }
            }
        }
    %>
 
    <center>
        <h2>쿠키 로그인</h2>
        <form action="CookieLoginProc.jsp" method="post">
            <table width="400" border="1">
                <!-- 테이블을 생성 -->
                <tr height="50">
                    <td width="150">아이디</td>
                    <td width="250"><input type="text" name="id" value="<%=id%>">
                    </td>
                </tr>
 
                <tr height="50">
                    <td width="150">패스워드</td>
                    <td width="250"><input type="password" name="pass"></td>
                </tr>
 
                <tr height="50">
                    <td colspan="2" align="center"><input type="checkbox"
                        name="save" value="1">아이디 저장</td>
                </tr>
 
                <tr height="50">
                    <td colspan="2" align="center"><input type="submit"
                        value="로그인"></td>
                </tr>
            </table>
 
        </form>
    </center>
 
</body>
</html>
cs

 

 

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
<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>
    <%
 
    request.setCharacterEncoding("EUC-KR");
 
 
    //아이디 저장 체크 박스가 체크되었는지 판단 여부
    String save = request.getParameter("save");
    
    //아이디 값을 저장
    String id = request.getParameter("id");
    
    //체크 되었는지 비교 판단
    if(save != null//아이디 저장이 눌렸다면
    {
        
        //쿠키를 사용하려면 쿠키클래스를 생성해 주어야 함.
        Cookie cookie = new Cookie("id",id); //디폴트 쿠키는 없다 (값을 넣어야 한다.)
                                        //1번째 String 키값을 적어줌
                                        //2번째는 해당 value 값을 넘겨줌
                                        //id 값을 id라는 이름으로 읽어들인다.
                
        //쿠키 유효시간 설정                                
        cookie.setMaxAge(60*3); //10분간 쿠키가 유효하다.    
                        
        response.addCookie(cookie); //사용자에게 쿠키를 넘겨준다.
        
        
        out.write("쿠키 생성완료");
    }
    
    
    
%>
 
 
 
 
</body>
cs

 

 

 

 

 

-Session 사용법-

 

사용자로부터 넘어온 클라이언트에 대한 정보를 서버측에서 저장하는 개념이다

세션을 사용하는 이유는 페이지가 바뀌어도 계속해서 데이터를 유지하고 싶을때 사용한다.

 

 

메소드 이름 

리턴 타입 

 설명

getAttribute(String name)

 java.lang.Object

 세션 속성명이 name인 속성의 값을 Object 타입으로 리턴한다. 해당되는

속성명이 없을 경우에는 null 값을 리턴한다.

getAttributeNames( )

java.util.Enumeration 

세션 속성의 이름들을 Enumeration 객체 타입으로 리턴한다. 

getCreationTime( ) 

long 

1970년 1월 1일 0시 0초를 기준으로 하여 현재 세션이 생성된

시간까지 경과한 시간을 계산하여 1/1000초 값으로 리턴한다. 

getld( ) 

java.lang.String 

 세션에 할당된 고유 식별자를 String 타입으로 리턴한다.

getMaxInactiveInterval( )

int 

현재 생성된 세션을 유지하기 위해 설정된 세션 유지시간을 int형으로 리턴한다.

invalidate( ) 

void 

현재 생성된 세션을 무효화 시킨다.

removeAttribute(String.name) 

void 

세션 속성명이 name인 속성을 제거한다.

setAttribute(String name, Object value) 

void 

세션 속성명이 name인 속성에 속성값으로 value를 할당한다.

setMaxInactiveInterval(int interval)

void 

 세션을 유지하기 위한 세션 유지시간을 초 단위로 설정한다.

 

 

-Cookie와 Session의 차이-

 

구분 

Cookie

Session

사용 class 및 Interface 

Cookie class 

httpSession Interface 

저장되는 값 

문자열 형태만 저장 가능 

자바에서 사용되는 모든 객체 저장 가능 

저장 장소 

클라이언트에 저장 

SessionID만 클라이언트에 저장하고 실제적인 값은 서버에 저장 

 

 

 

-예제 및 출력 결과-

 

로그인 페이지 (SessionLoginForm.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
<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>
    <center>
        <h2>세션 로그인</h2>
        <!-- 쿠키는 아이디를 저장해서 읽어들일수 있지만 세션은 그럴수 없다. -->
        <form action="SessionLoginProc.jsp" method="post">
            <table width="400" border="1">
 
                <!-- 테이블을 생성 -->
                <tr height="50">
                    <td width="150">아이디</td>
                    <td width="250"><input type="text" name="id"></td>
                </tr>
 
                <tr height="50">
                    <td width="150">패스워드</td>
                    <td width="250"><input type="password" name="pass"></td>
                </tr>
 
                <tr height="50">
                    <td colspan="2" align="center"><input type="submit"
                        value="로그인"></td>
                </tr>
            </table>
        </form>
    </center>
 
</body>
</html>
cs

 

 

로그인을 처리하는 페이지 1 (request로 자료를 읽어들인다.) (SessionLoginProc.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
<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>
    <center>
 
        <h2>세션 로그인 처리 1</h2>
 
        <% 
    request.setCharacterEncoding("EUC-KR"); //한글 깨짐을 방지하기 위해 문자셋 설정
 
    //사용자로부터 데이터를 읽어들인다.
    String id = request.getParameter("id"); //id와 pass를 각각 변수에 저장
    String pass = request.getParameter("pass");
    
    //아이디와 패스워드를 저장
    session.setAttribute("id", id);
    session.setAttribute("pass", pass);
    
    //세션의 유지시간 설정
    session.setMaxInactiveInterval(60);
    
%>
        <h2>
            당신의 아이디는
            <%=id %>
            입니다. 패스워드는
            <%=pass %>
            입니다.
        </h2>
        <!-- 아이디 출력 -->
        <a href="SessionLoginProc2.jsp?id=<%=id %>&pass=<%=pass%>">다음페이지로
            이동</a>
 
        <!--  <a href="SessionLoginProc2.jsp?id=<%=id %>&pass=<%=pass%>">다음페이지로 이동</a> 이렇게 써도 값은 넘어가지만 패스워드가 url에 공개되서 보안상 문제가 있으므로 세션을 써야한다.-->
    </center>
 
</body>
</html>
cs

 

 

로그인을 처리하는 페이지 2 (Session로 자료를 읽어들인다.) (SessionLoginProc2.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
<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>
    <center>
        <h2>세션 로그인 처리 2</h2>
 
        <%
            //세션에 저장되어 있는 아이디와 비밀번호를 각각 변수에 저장함 세션에서 출력할때는 오브젝트 타입이기 때문에 (타입변환 실시)
            String id = (String) session.getAttribute("id");
            String pass = (String) session.getAttribute("pass");
        %>
        <h2>
            당신의 아이디는
            <%=id%>
            입니다.
        </h2>
        <h2>
            당신의 비밀번호는
            <%=pass%>
            입니다.
        </h2>
 
    </center>
</body>
</html>
cs

 

 

:

19.05.04 JSP와 데이터베이스 연동 -2 (동영상 30강~32강)

Back-End/JSP 2019. 5. 4. 23:12

데이터베이스 테이블 생성

 

1
2
3
4
5
6
7
8
CREATE TABLE MEMBER(id CHAR(20),
pass1 CHAR(20),
email CHAR(30),
tel CHAR(50),
hobby CHAR(30),
job CHAR(40),
age CHAR(20),
info CHAR(20));
cs

 

 

회원 삭제, 수정, 개인정보 보기 추가

 

 

 

회원 가입 (MemberJoin.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
<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
 
<center>
    <h2>회원 가입</h2>
    <body>
        <form action="MemberJoinProc.jsp" method="post">
            <table width="500" border="1">
 
                <tr height="50">
                    <td width="150" align="center">아이디</td>
                    <td width="350" align="center"><input type="text" name="id"
                        size="40" placeholder="id를 넣으세요."></td>
                <tr height="50">
                    <td width="150" align="center">패스워드</td>
                    <td width="350" align="center"><input type="password"
                        name="pass1" size="40" placeholder="비밀번호는 영문과 숫자만 넣어주세요."></td>
                <tr height="50">
                    <td width="150" align="center">패스워드 확인</td>
                    <td width="350" align="center"><input type="password"
                        name="pass2" size="40"></td>
                <tr height="50">
                    <td width="150" align="center">이메일</td>
                    <td width="350" align="center"><input type="email"
                        name="email" size="40" placeholer></td>
                <tr height="50">
                    <td width="150" align="center">전화번호</td>
                    <td width="350" align="center"><input type="tel" name="tel"
                        size="40"></td>
                <tr heigth="50">
                    <td width="150" align="center">당신의 관심분야</td>
                    <td width="350" align="center"><input type="checkbox"
                        name="hobby" value="캠핑">캠핑 &nbsp;&nbsp; <input
                        type="checkbox" name="hobby" value="등산">등산 &nbsp;&nbsp; <input
                        type="checkbox" name="hobby" value="영화">영화 &nbsp;&nbsp; <input
                        type="checkbox" name="hobby" value="독서">독서 &nbsp;&nbsp;</td>
                </tr>
                <tr heigth="50">
                    <td width="150" align="center">당신의 직업은</td>
                    <td width="350" align="center"><select name="job">
                            <option value="교사">교사</option>
                            <option value="변호사">변호사</option>
                            <option value="의사">의사</option>
                            <option value="기술사">기술사</option>
                    </select></td>
                </tr>
                <tr height="50">
                    <td width="150" align="center">당신의 연령은</td>
                    <td width="350" align="center"><input type="radio" name="age"
                        ㄴㄴ
                        value="20">20대&nbsp;&nbsp; <input
                        type="radio" name="age" value="30">30대&nbsp;&nbsp; <input
                        type="radio" name="age" value="40">40대&nbsp;&nbsp;</td>
                </tr>
 
                <tr height="50">
                    <td width="150" align="center">하고싶은말</td>
                    <td width="350" align="center"><textarea rows="5" cols="40"
                            name="info"></textarea></td>
                </tr>
 
                <tr height="50">
                    <td align="center" colspan="2"><input type="submit"
                        value="회원 가입"> <input type="reset" value="취소">
            </table>
        </form>
</center>
</body>
</html>
 
cs

 

 

자바빈 클래스(회원을 정보를 저장) (MemberBean.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
package ch11;
 
public class MemberBean { //자바빈 클래스
    
    private String id;
    private String pass1;
    private String pass2;
    private String email;
    private String tel;
    private String hobby;
    private String job;
    private String age;
    private String info;
    
    
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getPass1() {
        return pass1;
    }
    public void setPass1(String pass1) {
        this.pass1 = pass1;
    }
    public String getPass2() {
        return pass2;
    }
    public void setPass2(String pass2) {
        this.pass2 = pass2;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public String getTel() {
        return tel;
    }
    public void setTel(String tel) {
        this.tel = tel;
    }
    public String getHobby() {
        return hobby;
    }
    public void setHobby(String hobby) {
        this.hobby = hobby;
    }
    public String getJob() {
        return job;
    }
    public void setJob(String job) {
        this.job = job;
    }
    public String getAge() {
        return age;
    }
    public void setAge(String age) {
        this.age = age;
    }
    public String getInfo() {
        return info;
    }
    public void setInfo(String info) {
        this.info = info;
    }
    
    
    
}
 
cs

 

 

회원가입한 정보를 빈클래스로 옮겨주는 파일 (MemberJoinProc.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
<%@page import="ch11.MemberDAO"%>
<%@page import="java.sql.PreparedStatement"%>
<%@page import="java.sql.DriverManager"%>
<%@page import="java.sql.Connection"%>
<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>
 
    <%
        request.setCharacterEncoding("EUC-KR"); //한글 처리
 
        //취미 부분은 별도로 읽어들여 다시 빈클래스에 저장
 
        String[] hobby = request.getParameterValues("hobby");
        //배열에 있는 내용을 하나의 스트림으로 저장
        String texthobby = "";
 
        for (int i = 0; i < hobby.length; i++) {
            texthobby += hobby[i] + " "//취미를 배열을 사용해 하나씩 출력해서 texthobby에 넣는다.
        }
    %>
 
    <!-- useBean을 이용하여 한꺼번에 데이터를 받아옴 -->
    <!-- 맵핑 시키시오 -->
    <jsp:useBean id="mbean" class="ch11.MemberBean">
        <jsp:setProperty name="mbean" property="*" />
    </jsp:useBean>
 
    <%
        mbean.setHobby(texthobby); //기존 취미는 주소번지가 저장되기에 위에 배열의 내용을 하나의 스트림으로 저장한 변수를 다시 입력
 
        MemberDAO mdao = new MemberDAO(); //insert 메소드를 사용하기 위해 MemberDAO 객체 생성
        mdao.insertMember(mbean); //insert메소드를 호출해 mbean에 저장된 값을 넘겨주면 그 값이 데이터베이스에 저장된다.
    %>
 
    오라클에 접속 완료 ~
 
</body>
</html>
 
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
package ch11;
 
import java.sql.*//SQL 패키지인지 반드시 확인
import java.util.Vector;
//*을 쓰면 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 {
            // 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

 

 

모든 회원의 정보를 보는 파일 (MemberList.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 import="java.util.Vector"%>
<%@page import="ch11.MemberDAO"%>
<%@page import="ch11.MemberBean"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>
 
    <!-- 1.데이터 베이스에서 모든 회원의 정보를 가져옴  2. table태그를 이용하여 화면에 회원들의 정보를 출력-->
 
    <%
        //회원들의 정보가 얼마나 저장되어있는지 모르기에 (배열은 길이가 고정되어 있기 때문에 List나 벡터를 쓴다.) (List,벡터는 가변길이를 지원)
        MemberDAO mdao = new MemberDAO();
        Vector<MemberBean> vec = mdao.allSelectMember();
        //MemberBean클래스를 안넣어주면 기본적으로 벡터는 오브젝트 클래스이기때문에 다시 캐스팅을 해주어야한다.
    %>
 
    <center>
        <h2>모든 회원 보기</h2>
        <table width="800" border="1">
            <tr height="50">
                <td align="center" width="150">아이디</td>
                <td align="center" width="250">이메일</td>
                <td align="center" width="200">전화번호</td>
                <td align="center" width="200">취미</td>
            </tr>
            <%
                for (int i = 0; i < vec.size(); i++) {
                    MemberBean bean = vec.get(i); //벡터에 담긴 빈클래스를 하나씩 추출
            %>
            <tr height="50">
                <td align="center" width="150"><a
                    href="MemberInfo.jsp?id=<%=bean.getId()%>"> <!-- MemberInfo.jsp로 얻은 Id를 넘겨준다. -->
                        <%=bean.getId()%></a></td>
                <td align="center" width="250"><%=bean.getEmail()%></td>
                <td align="center" width="200"><%=bean.getTel()%></td>
                <td align="center" width="200"><%=bean.getHobby()%></td>
            </tr>
 
            <%
                }
            %>
        </table>
    </center>
</body>
</html>
 
cs

 

 

한명의 개인정보를 보는 파일 (MemberInfo.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
<%@page import="ch11.MemberBean"%>
<%@page import="ch11.MemberDAO"%>
<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
</head>
<body>
    <!-- memberlist에서 넘긴 id를 받아줌  1.데이터베이스에서 한 사람의 정보를 가져옴   2. table 태그를 이용하여 화면에 회원의 정보 출력 -->
 
    <%
        String id = request.getParameter("id");
 
        MemberDAO mdao = new MemberDAO();
        MemberBean mbean = mdao.oneSelectMember(id);
    %>
 
    <center>
        <h2>회원 정보 보기</h2>
 
        <table width="400" border="1">
 
            <tr height="50">
                <td align="center" width="150">아이디</td>
                <td width="250"><%=mbean.getId()%></td>
            <tr height="50">
                <td align="center" width="150">이메일</td>
                <td width="250"><%=mbean.getEmail()%></td>
            <tr height="50">
                <td align="center" width="150">전화</td>
                <td width="250"><%=mbean.getTel()%></td>
            <tr height="50">
                <td align="center" width="150">취미</td>
                <td width="250"><%=mbean.getHobby()%></td>
            <tr height="50">
                <td align="center" width="150">직업</td>
                <td width="250"><%=mbean.getJob()%></td>
            <tr height="50">
                <td align="center" width="150">나이</td>
                <td width="250"><%=mbean.getAge()%></td>
            <tr height="50">
                <td align="center" width="150">정보</td>
                <td width="250"><%=mbean.getInfo()%></td>
            </tr>
 
            <tr height="50">
                <td align="center" colspan="2">
                    <!-- submit은 폼데이터시에만 쓸수 있음 (데이터를 보낼때) -->
                    <button
                        onclick="location.href='MemberUpdateForm.jsp?id=<%=mbean.getId()%>'">회원수정</button>
                    <!-- onclick는 다른페이지로 이동 -->
                    <button
                        onclick="location.href='MemberDeletForm.jsp?id=<%=mbean.getId()%>'">회원삭제</button>
                    <!-- 빈클래스의 id를 페이지 이동시에 같이 넘긴다. -->
                    <button
                        onclick="location.href='MemberList.jsp?id=<%=mbean.getId()%>'">목록보기</button>
                    <button
                        onclick="location.href='MemberJoin.jsp?id=<%=mbean.getId()%>'">회원가입</button>
                </td>
            </tr>
 
            </center>
        </table>
</body>
</html>
cs

 

 

회원 정보 수정 파일 (MemberUpdateForm.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
<%@page import="ch11.MemberBean"%>
<%@page import="ch11.MemberDAO"%>
 
<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>
    <%
        String id = request.getParameter("id");
        MemberDAO mdao = new MemberDAO();
        MemberBean mbean = mdao.oneSelectMember(id);
    %>
 
    <center>
        <h2>회원 정보 수정 하기</h2>
 
        <table width="400" border="1">
            <form action="MemberUpdateProc.jsp" method="post">
            <tr height="50">
                <td align="center" width="150">아이디</td>
                <td width="250"><%=mbean.getId()%></td>
            </tr>
 
            <tr height="50">
                <td align="center" width="150">이메일</td>
                <td width="250"><input type="email" name="email"
                    value="<%=mbean.getEmail()%>"></td>
            </tr>
            <!-- 이메일의 값을 바꾸는 것이므로 value값에 getEmail()을 넣는다.-->
 
            <tr height="50">
                <td align="center" width="150">전화</td>
                <td width="250"><input type="tel" naem="tel"
                    value="<%=mbean.getTel()%>"></td>
 
            </tr>
 
            <tr height="50">
                <td align="center" width="150">패스워드</td>
                <td width="250"><input type="password" name="pass1"></td>
                <!-- 패스워드를 입력하고 결과가 맞아야만 정보 수정 가능 -->
                </td>
            </tr>
 
 
            <tr height="50">
                <td align="center" colspan="2">
                    <!-- submit은 폼데이터시에만 쓸수 있음 (데이터를 보낼때) --> <input type="hidden"
                    name="id" value="<%=mbean.getId()%>"> <!--hidden은 안보이게 넘기는것 즉,아이디 값을 안보이게 넘긴다는 것 -->
                    <input type="submit" value="회원 수정하기"> &nbsp;&nbsp;
                    </form>
                    <button onclick="location.href='MemberList.jsp'">회원 전체 보기
                    </button> <!-- 회원 전체보기 페이지로 돌아감 -->
                </td>
                </center>
        </table>
</body>
</html>
cs

 

 

 

회원 정보 수정 파일 (MemberUpdateProc.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
<%@page import="ch11.MemberDAO"%>
<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>
    <%
    request.setCharacterEncoding("EUC-KR");
%>
 
    <jsp:useBean id="mbean" class="ch11.MemberBean">
        <!-- 기존에 있는 데이터만 들어가고 나머지는 null로 들어가기 때문에 문제가 없다. -->
        <jsp:setProperty name="mbean" property="*" />
        <!-- 또한 null이 들어가도, null이 된 자료를 빼는것이 아니기 때문에 문제가 없다. -->
    </jsp:useBean>
    <% 
    String id = request.getParameter("id");
 
    MemberDAO mdao = new MemberDAO(); //메소드를 호출하기 위해 객체 생성
    String pass = mdao.getPass(id); //String 타입으로 저장되어있는 패스워드를 가져옴 (데이터베이스에서 가져온 pass 값이 저장)
 
    //수정하기위해서 작성한 패스워드값과 기존 데이터베이스에서 가져온 패스워드 값을 비교
    
    if(mbean.getPass1().equals(pass)) //기존 패스워드와 데이터베이스의 패스가 같다면 member테이블을 수정
    {
        //MemberDAO 클래스의 회원수정 메소드를 호출
        mdao.updateMember(mbean);
        response.sendRedirect("MemberList.jsp"); //멤버리스트 파일로 넘어간다.
    }
    else
    {
%>
    <script type="text/javascript">
     alert("패스워드가 맞지 않습니다. 다시 확인해 주세요"
     history.go(-1);
     </script>
    <%     
    }
%>
</body>
</html>
cs

 

 

 

회원 정보 삭제 파일 (MemberDeleteForm.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
<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>
 
 
    <center>
        <h2>회원 삭제 하기</h2>
 
        <table width="400" border="1">
            <form action="MemberDeleteProc.jsp" method="post">
                <tr height="50">
 
                    <td align="center" width="150">아이디</td>
                    <td width="250"><%=request.getParameter("id")%></td>
                </tr>
            <tr height="50">
                <td align="center" width="150">패스워드</td>
                <td width="250"><input type="password" name="pass1"></td>
                <!-- 패스워드를 입력하고 결과가 맞아야만 정보 삭제 가능 -->
                </td>
            </tr>
 
 
            <tr height="50">
                <td align="center" colspan="2">
                    <!-- submit은 폼데이터시에만 쓸수 있음 (데이터를 보낼때) --> <input type="hidden"
                    name="id" value="<%=request.getParameter("id")%>"> <!--hidden은 안보이게 넘기는것 즉,아이디 값을 안보이게 넘긴다는 것 -->
                    <input type="submit" value="회원 삭제하기"> &nbsp;&nbsp;
            </form>
            <button onclick="location.href='MemberList.jsp'">회원 전체 보기</button>
            <!-- 회원 전체보기 페이지로 돌아감 -->
            </td>
            </tr>
 
        </table>
    </center>
 
 
 
 
</body>
</html>
cs

 

 

회원 정보 삭제 파일 (MemberDeleteProc.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
<%@page import="ch11.MemberDAO"%>
<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>
 
    <%
    request.setCharacterEncoding("EUC-KR");
%>
 
    <jsp:useBean id="mbean" class="ch11.MemberBean">
        <!-- 기존에 있는 데이터만 들어가고 나머지는 null로 들어가기 때문에 문제가 없다. -->
        <jsp:setProperty name="mbean" property="*" />
        <!-- 또한 null이 들어가도, null이 된 자료를 빼는것이 아니기 때문에 문제가 없다. -->
    </jsp:useBean>
    <% 
 
    MemberDAO mdao = new MemberDAO(); //메소드를 호출하기 위해 객체 생성
    String pass = mdao.getPass(mbean.getId()); //String 타입으로 저장되어있는 패스워드를 가져옴 (데이터베이스에서 가져온 pass 값이 저장)
 
    //수정하기위해서 작성한 패스워드값과 기존 데이터베이스에서 가져온 패스워드 값을 비교
    
    if(mbean.getPass1().equals(pass)) //기존 패스워드와 데이터베이스의 패스가 같다면 member테이블을 수정
    {
        //MemberDAO 클래스의 회원수정 메소드를 호출
        mdao.deleteMember(mbean.getId());
        response.sendRedirect("MemberList.jsp"); //멤버리스트 파일로 넘어간다.
    }
    else
    {
%>
    <script type="text/javascript">
     alert("패스워드가 맞지 않습니다. 다시 확인해 주세요"
     history.go(-1);
     </script>
    <%     
    }
%>
 
 
</body>
</html>
cs
:

19.05.04 백업과 복구

Back-End/Data Base 2019. 5. 4. 21:12

-DBMS의 3가지 구조-

 

DBMS에서 데이터를 보존하는 기억장치는 대부분 하드디스크입니다.

하드디스크에서 지속성을 실현하려면 쓰기를 전부 '동기화쓰기' 로 하면 좋겠지만, 데이터베이스의 쓰기는

기억장치의 임의 장소에 무작위로 액세스해서 쓰기를 수행하기 때문에 동기화 쓰기는 느려서 성능 면에서

실용적이지 않습니다.

그래서 지속성과 성능이 양립하도록 일반적으로 DBMS에서는 3가지 구조를 사용합니다.

 

 

 

-로그 선행 쓰기(WAL)-

 

데이터베이스의 데이터 파일 변경을 직접 수행하지 않고, 우선 로그로 변경 내용을 기술한 로그 레코드를 써서

동기화하는 구조입니다.

MySQL 에서는 이 로그를 'InnoDB 로그' 로 부릅니다.

WAL에는 다음과 같은 이점이 있습니다.

 

 

  1. 디스크에 연속해서 쓰기 때문에 무작위로 쓰는 것보다 성능이 좋다.

 

  2. 디스크에 쓰는 용량과 횟수를 줄일 수 있다.

 

  3. 데이터베이스 버퍼를 이용해 데이터베이스의 데이터 파일로의 변경을 효율성 높게 수행한다.

 

 

 

 

-데이터베이스 버퍼-

 

커밋 시에는 WAL에 변경 내용을 쓰기 때문에 데이터 파일의 변경 내용은 트랜잭션이 커밋되면서 동시에 동기화할

필요가 없습니다.

그렇다고 트랜잭션마다 버퍼를 취해 비동기적인 쓰기를 하면 로그와 데이터 파일 간 일관성을 유지하기가 어렵습니다.

그래서 일반적인 DBMS에서는 '데이터베이스 버퍼' 를 준비해 데이터 파일로의 입력을 데이터베이스 버퍼 경유로

일원화해서 단순화하고 있습니다.

이 때문에 효율적으로 데이터의 일관성을 유지할 수 있게 됩니다.

MySQL의 경우 갱신의 흐름은 다음과 같습니다.

 

 

  1. 갱신 대상의 데이터를 포함한 페이지가 버퍼풀(버퍼)에 있는지를 확인하고 없다면 데이터 파일로부터 읽어 들인다.

 

  2. 버퍼 풀의 해당 페이지에서 갱신을 수행한다.

 

  3. 2의 갱신 내용이 커밋과 함께 로그에 기록된다. 버퍼풀에 갱신되었지만, 아직 데이터 파일에 써지지 않은 페이지는

     버퍼 풀 내에서 더티 페이지(메모리로 읽어서 갱신된 페이지)로 다룬다.

 

  4. 데이터 페이지는 나중에 적당한 타이밍에 정리되어 데이터 파일로 써진다 (이것을 '체크포인트' 라고 부른다.)

 

  5. 4의 체크포인트 이전 로그 파일은 불필요해진다. 또한, 갱신과 더불어 1부터 순서가 반복된다.

 

 

 

 

-크래시 복구-

 

WAL과 데이터베이스 버퍼, 데이터베이스 파일 3가지가 연계 플레이로 지속성을 담보하면서 현실적인 성능으로 DBMS가 동작하고 있습니다.

크래시 (예를 들면, MySQL 서버의 비정상적 종료)가 발생한 경우의 복구.

 

크래시가 발생하면 다음과 같은 상태가 됩니다.

 

 

  1. WAL : 마지막으로 커밋된 트랜잭션의 갱신 정보를 가진다.

 

  2. 데이터베이스 버퍼 : 크래시로 내용이 전부 소실된다.

 

  3. 데이터베이스 파일 : 최후 체크포인트까지의 갱신 정보를 가진다.

 

 

 

 

-PITR이란?-

 

일반적인 DBMS에서는 데이터베이스에 실행된 갱신을 기록한 로그를 보존해서 그것을 복원한 데이터베이스에 순차 반영해 백업 이후의

임의의 시점으로 복원할 수 있습니다.

이처럼 임의의 시점에서의 데이터 변경을 포함한 복원을 'PITR (Point - in - time Recovery)' 라고 부릅니다.

PITR에 이용되는 로그의 이름과 특성은 DBMS마다 다르다.

 

DBMS 

Oracle 

MySQL 

PostgreSQL 

DB2 

SQL Server 

로그 이름

REDO 로그

바이너리 로그

WAL 로그

트랜잭션 로그

트랜잭션 로그

아카이브 지정

X (본문 참조) 

아카이브 시 이름 

ARCHIVELOG

WAL 아카이브 

아카이브 로깅 

완전 복구 모델

비 아카이브 시 이름 

NOARCHIVELOG 

(없음) 

순환 로깅 

완전 복구 모델 

 

 

 

-아카이브 지정이란?-

 

PITR에 이용하는 로그는 대부분 앞에서 설명한 WAL을 이용합니다.

이 때문에 WAL을 크래시 복구에만 이용한다면 체크포인트 이전의 로그는 불필요하게 되어 해당 디스크 영역은

삭제하거나 재이용할 수 있습니다. (다시 이용되는 경우가 대부분)

하지만 이렇게 되면 PITR을 수행하고 싶을 때에 필요한 로그가 없는 사태가 발생하게 됩니다.

따라서 크래시 복구용으로는 불필요한 로그도 PITR 용으로 보존이 필요할 수 있으며 이를 위한 모드가 '아카이브 지정' 입니다.

 

 

 

-바이너리 로그란?-

 

MySQL에서 PITR에는 '바이너리 로그'를 이용하는데, 앞의 로그 선행 쓰기에 나왔던 InnoDB 로그는 이용하지 않는지 궁금할 수 있습니다.

실은 InnoDB 로그는 InnoDB 전용 크래시 복구에만 이용되고, PITR에는 MySQL 전체 (InnoDB에 한정하지 않고) 에서 이용하는

바이너리 로그를 채용합니다.

 

 

 

-백업-

 

장애가 발생하면 데이터베이스의 데이터는 이용할 수 없게 됩니다.

이런 사태에 신속히 대응하기 위해 데이터베이스가 정상적인 상태일 때 현재 이용하는 데이터를 복제해서 어딘가 다른 장소에 옮겨

두어야 합니다. 이 옮겨진 데이터를 '백업 데이터' 라고 하며 이 데이터를 얻어내는 과정을 '백업' 이라고 부릅니다.

장애가 발생하면 신속하게 백업한 데이터에서 데이터베이스의 데이터를 이용할 수 있는 상황까지 복구합니다.

이것이 '복원 (Restore)' 입니다.

 

백업을 수행하는 데는 다음 3가지 관점이 있습니다.

 

 

  1. 핫 백업과 콜드 백업

 

  2. 논리 백업과 물리 백업

 

  3. 풀 백업과 부분 (증분 / 차등) 백업

 

 

 

핫 백업

콜드 백업 

'온라인 백업' 이라고도 하며 백업 대상의 데이터베이스를 정지하지

않고 가동한채로 백업 데이터를 얻습니다.

핫 백업에서는 데이터베이스를 가동한 채로 백업 데이터를 얻는데,

어떤 도구를 사용하는지, 획득 수단은 무엇인지에 따라 차이가 있습니다.

 '오프라인 백업' 으로 불리며 백업 대상의 데이터베이스를

정지한 후 백업 데이터를 얻습니다.

MySQL에서는 MySQL 서버를 셧다운해서 데이터 디렉터리에 있는

디렉터리와 파일을 전부 OS 명령으로 복사합니다.

 

 

 

구분 

논리 백업 

물리 백업 

장점

  * 편집할 수 있다. 텍스트를 변경해 백업된 내용 일부를

    수정할 수 있다.

 

  * 이식성이 우수하다. 텍스트 변경으로 (CSV 등은 변경 없이)

    동일한 DBMS의 다른 버전이나 다른 DBMS에 복원할 수 있다.

 * 최소 크기로 데이터를 얻을 수 있다. 데이터의 교환이 없어서

   (또는 최소) 백업과 복원 속도가 빠르다.

단점

 * 물리 백업보다 크기가 크다. 바이너리와 텍스트 상호교환에

   들어가기 위한 백업과 복원의 동작 속도가 느리다.

 * 복원 단위는 도구에 따라 다르며 일부 데이터의 교환이나 적용

   등이 불가능 하다.

 

 * 플랫폼 의존 바이너리는 동일한 DBMS라도 호환되지 않는다.

 

 

 

구분 

풀 백업 

부분 백업 

 장점

 * 백업 데이터가 한군데에 모여 있어서 복원 처리가 단순하다.

 * 갱신한 데이터만을 대상으로 하므로 백업에 필요한 시간이 짧고,

    백업 데이터의 용량이 작아도 문제없다.

 단점

 * 데이터베이스 전체를 백업하므로 백업에 걸리는 시간이 길다.

 

 * 갱신량이 적어도 매일 데이터베이스 전체를 백업하므로

    백업 데이터를 저장하는데 충분한 용량이 필요하다.

 * 복원에는 풀 백업과 부분 백업이 필요해서 복원 절차가 복잡하다.

 

 

 

   단원 정리

 

  - 데이터베이스에는 ACID 특성 중 'Durability(지속성)' 에 의해 커밋된 내용이 영속화 되기 때문에 데이터를 잃어버리는 경우는 없다.

 

  - 데이터파일이 있는 파일 시스템의 파손이나 서버, 디스크의 물리 장애에 대비하기 위해 '백업' 프로세스가 필요하다.

 

  - 백업 관점에는 DBMS 정지 여부 (콜드와 핫), 형식 (논리와 물리), 범위 (풀과 차등 / 증분) 가 있다.

 

  - 기본 백업 방식은 풀 백업이지만, 필요에 따라 차등 / 증분 백업을 검토한다.

 

  - 백업에 걸리는 시간과 부하, 복원과 복구에 걸리는 시간을 고려한다.

 

 

 

 

 

 

 

:

19.05.03 테이블의 개념과 정규형

Back-End/Data Base 2019. 5. 3. 23:31

-테이블 이란?-

 

각각의 행이 어떤 공통적인 특징을 가진 집합이어야 한다.

또한 테이블은 현실 세계를 반영한다. ('개념' 이나 '집합' 으로)

 

 

 

-열 이란?-

 

개체의 속성을 의미한다.

 

 

 

-기본키-

 

테이블 안에 있는 객체를 구분할 수 있는 키.

또한 기본키는 중복되거나 NULL 값이 올 수 없다. (다른 객체를 구분할 수 없기 때문)

그리고 기본키는 값이 바뀌면 곤란하다. (변경 후 값의 유일성을 보증할 수 없고, 과거 데이터와의 결합이 어렵다.)

 

 

 

-정규형-

 

데이터의 갱신이 발생한 경우에도 부정합이 발생하기 어려운 테이블의 형태 (이상현상을 방지하기 위해 테이블을 무손실 분해하는것)

 

 

 

-제 1정규형-

 

테이블 셀에 복합적인 값을 포함하지 않는다 (하지만 관계형 데이터베이스에서는 이 정의에 반하는 테이블을 작성하는 것이 기술적으로 불가)

복합적인 값을 셀에 넣으면 기본키가 행의 값을 고유하게 특정할 수 없기 때문.

 

 

-비 제1정규형 테이블-

 

사원 ID 

이름 

나이 

성별 

피부양자 

S001

김미경 

38 

여 

박초롱 

S002 

박유안 

30 

남 

박안나 

S003 

이관식 

62 

남 

(이수빈, 이수인) 

 

 

 

-함수 종속성-

 

기본키와 다른 열 사이에 성립하는 함수적인 유일성을 관계형 데이터베이스에서는 '함수 종속성' 이라고 하며 다음과 같이 열을

중괄호 ({ })로 감싸서 화살표(->)로 연결해 표현 합니다.

 

 

  {사원 ID} -> {이름}

 

 

 

 

-제 2정규형-

 

제 1정규형을 만족하고 부분함수 종속성을 제거한 정규형을 말한다.

(기본키는 현재 고객 기업 ID와 주문번호 인데, 고객기업 ID만으로도 기업명과 고객 기업규모를 특정할수 있어 주문번호 열이 쓸데없는 값이 되기 때문)

이와 같은 부분함수 종속이 존재할 경우 해당 키와 종속하는 열만 다른 테이블로 만들어 외부로 꺼내야 합니다.

비정규형 테이블을 사용할 때 같은 내용의 행이 복수 행 존재할수 있으므로 일부가 잘못 등록될 위험이 있기 때문에 제 2정규형을 사용한다.

 

-비 제2정규형 테이블-

 

고객기업 ID 

주문번호 

주문접수일 

고객기업명 

고객기업 규모 

CA

O001

2014 / 12 / 20

A 상사

대규모

CA

O002

2014 / 12 / 21 

A 상사

대규모 

CB 

O001

2014 / 12 / 12

B 건설 

중규모 

CB

O002 

2014 / 12 / 25

B 건설 

중규모 

CB

O003 

2014 / 12 / 25

B 건설 

중규모 

CC

O001 

2014 / 12 / 1

C 화학 

소규모 

 

 

 

-제 3정규형-

 

제 2정규형을 만족하고, 이행 함수 종속을 제거한 정규형을 말한다.

(예를 들어 아래 테이블에서 앞으로 관리하고 싶은 업계는 석유, 건설, 바이오 외에도 시스템 또는 유통 등 다양하다고 해도 지금은

이 테이블에 해당 업계를 등록할 방법이 없습니다. 이 테이블이 '기업' 이라는 단위의 집합을 반영하고 있어서 '유통' 이라는 업계에 속한

기업과 거래를 하지 않은 이상 해당 업계의 레코드를 만들 수 없기 때문입니다.)

 

-비 제3정규형 테이블-

 

고객기업 ID 

고객기업명 

고객기업규모 

업계코드 

계명 

CA

A상사

대규모

D001

석유

CB 

B건설 

중규모 

D002 

건설 

CC 

C화학 

소규모 

D003 

바이오 

 

 

 

  {고객기업 ID} -> {업계코드} -> {업계명} //(고객기업 ID가 업계코드를 정하고 업계코드가 업계명을 정하는 함수종속을 '이행함수종속'이라 한다)

 

 

 

 

-ER 다이어그램-

 

정규화를 수행하면 테이블이 나누어져 그 수가 증가하게 되는데 '갱신 이상'의 위험을 없애는 것이 목적이지만, 결과적으로 테이블 수가

늘어나는 것도 사실입니다. 이런 테이블 간의 관련성을 한눈에 알 수 있게 고안된 기술이 ER 다이어그램 입니다.

Entity(엔티티, 실체)란 '테이블' , 'Relationship(릴레이션십, 관계, 관련성)' 이란 '테이블 간의 관계' 를 의미합니다.

이를 표시하는데 그래픽으로 이해하기 쉽도록 해주는 기술이 ER 다이어그램 입니다.

 

 

 

-엔터티란?-

 

간단히 설명하면 테이블과 같고 사각형으로 표시합니다.

복잡한 정보를 간략화하기 위한 기술.

위 절반의 부분에는 '기본키'를 아래 절반의 부분에는 '기타 열(기본키가 아닌 열)'을 기재합니다.

 

 업계코드(PK)

 업계명

 

 

 

-릴레이션십이란?-

 

외래키가 존재하는 테이블은 해당 열이 다른 테이블의 기본키 열을 참조하는 것을 의미합니다.

이 관련성을 '릴레이션십' 이라고 합니다.

 

:

19.05.03 트랜잭션과 동시성 제어

Back-End/Data Base 2019. 5. 3. 22:39

-트랜잭션-

 

데이터베이스를 사용하는 실제 시스템이나 애플리케이션에서는 단일 쿼리만으로 조작하는 일은 거의 없고

복수의 쿼리를 연속적으로 사용해 일관성 있는 형태의 한 단위로 취급해야한다.

이러한 한 덩어리의 쿼리 처리 단위를 '트랜잭션'이라고 합니다.

 

MySQL에서는 트랜잭션을 사용할 수 없는 단순한 구조의 'MyISAM형'과 일반적인 DBMS와 똑같은

트랜잭션 구조를 사용할 수 있는 'InnoDB형' 2종류의 테이블을 이용할 수 있습니다.

이번 장에서는 트랜잭션을 사용하기 위해 InnoDB형 테이블을 작성합니다.

 

 

 

-트랜잭션의 4가지 특성(앞글자를 따서 'ACID 특성'이라고 한다.)-

 

 

  1. Atomicity (원자성) = 데이터의 변경 (INSERT/DELETE/UPDATE)을 수반하는 일련의 데이터 조작이

     전부 성공할지 실패할지 보증하는 구조 (전부 성공하거나 실패하거나)

 

  2. Consistency (일관성) = 일련의 데이터 조작 전후에 그 상태를 유지하는 것 (예를들어 속성에 유일성 제약을 걸면 중복된 번호 저장 불가)

 

  3. Isolation (고립성 또는 격리성) = 일련의 데이터 조작을 복수 사용자가 동시에 실행해도 '각각의 처리가 모순없이 실행되는 것을 보증한다' 는 것

 

  4. Durability (지속성) = 일련의 데이터 조작(트랜잭션 조작)을 완료(COMMIT)하고 완료 통지를 사용자가 받는 시점에서 그 조작이 영구적이

      되어 그 결과를 잃지 않는 것을 나타냅니다.

 

 

SQL 문은 몇가지 키워드와 테이블명, 열명 등을 조합해 하나의 문장을 만들어 쿼리의 내용을 기술하는데, 이중 키워드는

처음부터 의미나 사용법이 정해져 있는 특별한 영단어입니다. SQL문은 DBMS에 줄 수 있는 명령의 종류에 따라

다음 3가지로 구분됩니다.

 

데이터 정의 언어 (DDL) 

 데이터 조작 언어 (DML)

 데이터 제어 언어 (DCL)

 

 DDL은 데이터를 저장하는 그릇인 스키마

(데이터베이스) 또는 테이블 등을 작성하거나

제거합니다. DDL로 구분된 명령에서는

CREATE, DROP,ALTER 등이 있습니다.

 

 DML은 테이블의 행을 검색하거나 변경하는데 사용할 수 있습니다. DML로 구분된 명령에는

'SELECT (행의 검색), INSERT (행의 추가), UPDATE (행의 갱신), DELETE (행의 제거)

등이 있습니다.

 DCL은 데이터베이스에서 실행한 변경을

확정하거나 취소하는데 사용합니다.

COMMIT, ROLLBACK 등이 있습니다.

 

 

 

-MySQL의 특성-

 

 

  1. 읽기를 수행할 경우 갱신 중이라도 블록되지 않는다 (읽기와 읽기도 서로 블록되지 않는다)

 

  2. 읽기 내용은 격리 수준에 따라 내용이 바뀌는 경우가 있다.

 

  3. 갱신 시 배타적 잠금을 얻는다. 잠금은 기본적으로 행 단위로 얻으며 트랜잭션이 종료할 때까지 유지한다.

 

  4. 갱신과 갱신은 나중에 온 트랜잭션이 잠금을 획득하려고 할 때 블록된다. 일정 시간을 기다리며 그 사이에 잠금을 획득할 수 없는 경우에는

    잠금 타임아웃이 된다.

 

  5. 갱신하는 경우 갱신 전의 데이터를 UNDO 로그로 '롤백 세그먼트' 라는 영역에 유지한다. 이 'UNDO 로그'는 용도가 2가진데, 첫 번째는

     갱신하는 트랜잭션의 롤백 시 갱신 전으로 되돌리는 것이고, 두 번째는 복수의 트랜잭션으로부터 격리 수준에 따라 대응하는 갱신 데이터를

     참조하는데 이용한다.

 

 

 

 

-트랜잭션 격리 수준별 외관-

 

 

  반복 읽기 : 최초 쿼리를 실행한 시점에 커밋된 데이터를 읽어 들입니다.

                이 시점에서는 커밋된 읽기와 같습니다. 같은 쿼리를 여러번 실행하면 최초 읽은 내용의 결과 세트가 반환됩니다.

          복수 회의 쿼리 실행 사이에 다른 트랜잭션이 커밋했어도 그 내용은 반영되지 않습니다.

 

  커밋된 읽기 : 쿼리를 실행한 시점에서 커밋된 데이터를 읽어 들입니다.

   같은 쿼리를 여러번 실행하면 그 사이에 다른 트랜잭션에서 커밋할 때가 있는데, 이 경우 최신 쿼리의 실행 개시

   시점에서 커밋된 데이터를 읽습니다.

 

  갱신을 수행하는 트랜잭션 자신 : 트랜잭션 격리 수준이나 COMMIT/ROLLBACK에 상관없이 자신이 수행했던 갱신은 즉시 볼 수가 있습니다.

 

 

 

 

-잠금 타임아웃이란?-

 

'갱신' 과 '참조'는 서로를 블록하지 않지만, '갱신' 과 '갱신' 이 부딪치는 경우에는 나중에 온 갱신이 잠금 대기 상태가 됩니다.

잠금을 건 쪽이 언제 잠금을 풀지 알 수 없어서 잠금 해제를 기다리고 있는 쪽에서는 잠금을 기다리거나 기다리지 않거나,

기다린다면 어느 정도 기다릴지를 (초수 지정이나 무한으로 기다린다) 설정할 수 있습니다.

이때 잠금 대기로 타임아웃이 발생하는 경우 DBMS로부터 롤백되는 단위가 다를 때가 있는데, 해당 트랜잭션 전체를

롤백하는 경우와 쿼리만 롤백하는 것입니다.

MySQL 에서는 잠금 대기로 타임아웃이 발생하면 롤백되는 것은 기본으로 오류가 발생한 쿼리 입니다.

트랜잭션 전체를 롤백하고 싶다면 다음 방법으로 할 수 있습니다.

 

 

  타임아웃 오류 후 명시적으로 ROLLBACK을 실행한다.

 

  innodb_rollback_on_timeout 시스템 변수를 설정한다.

 

 

 

 

-교착 상태란?-

 

예를 들어, 트랜잭션 A가 테이블 a의 잠금을 얻고 트랜잭션 B가 테이블 b의 잠금을 얻었다고 해보겠습니다.

이 잠금을 유지한 채 서로 잠금을 건 자원에 잠금이 필요한 처리(INSERT/UPDATE/DELETE)를 실행하면 아무리

기다려도 상황이 바뀌지 않는 상태가 되는 것을 '교착 상태' 라고 합니다.

 

 

 

-교착상태의 빈도를 낮추는 대책-

 

DBMS 전반적인 대책 

 MySQL의 대책

 

 1. 트랜잭션을 자주 커밋한다.

    트랜잭션이 작은 단위가 되어 교착상태의 가능성을 낮춘다.

 

 2. 정해진 순서로 테이블(행)에 액세스 하게 한다.

 

 3. 필요 없는 경우에는 읽기 잠금 획득(SELECT ~ FOR UPDATE 등)의

    사용을 피한다.

 

 4. 쿼리에 의한 잠금 범위를 더 좁히거나 잠금 정도를

     더 작은 것으로 한다.

 

 5. 한 테이블의 복수 행을 복수의 연결에서 순서 변경 없이

    갱신하면 교착 상태가 발생하기 쉽다.

    동시에 많은 연결에서 갱신 때문에 교착 상태가 자주 발생한다면

    테이블 단위의 잠금을 획득해 갱신을 직렬화하면 동시성은 떨어지지만

    교착상태는 회피할 수 있어서 전체 처리로 보면 좋은 예도 있다.

 

 6. 테이블에 적절한 인덱스를 추가해 쿼리가 이를 이용하게 한다.

    인덱스가 사용되지 않는 경우에는 필요한 행의 잠금이 아닌

    스캔한 행 전체에 대해 잠금이 걸리게 한다.

 

 

 

 

  단원 정리

 

  1. DBMS의 트랜잭션은 'ACID'의 특성이 있다.

 

  2. 트랜잭션은 원자성에 의해 전부 성공하거나 전부 실패하는 원칙으로 동작한다.

 

  3. 고립성에 따라 병렬 실행이 일관성 있게 수행된다.

 

  4. 트랜잭션에는 4가지 격리 수준이 있는데, 직렬화 기능 이외의 수준을 선택하면 3가지의 현상이 발생한다.

   실제 운용에서는 '커밋된 읽기' 또는 '반복 읽기'의 격리 수준을 이용한다.

 

  5. 트랜잭션에서 잠금 대기와 교착 상태는 피할 수 없으므로 적절히 대처하는 것이 필요하다.

 

  6. 오토커밋은 쿼리 단위로 커밋하는 설정인데, 주의해서 사용하지 않으면 트랜잭션의 혜택을 받지 못할뿐더러 성능에 악영향을 미친다.

 

 

:

19.05.03 JDBC로 데이터베이스 연동

Back-End/JSP 2019. 5. 3. 12:03

-JDBC-


JDBC는 데이터베이스를 다루기 위한 자바 API(Application Programming Interface).

자바를 기반으로 하는 프로그램을 작성할 때 프로그래머에게 데이터베이스를 쉽게 다룰 수 있도록 해주는 것

JDBC를 통해서 어떠한 DBMS일지라도 질의문을 던져서 데이터를 가져올 수 있는 것입니다.


- 구성 : JDBC 인터페이스 + JDBC 드라이버

- 목적 : 데이터베이스 연동 자바 프로그램시 인터페이스의 사용만으로 데이터베이스를 다루기 위함


JDBC 인터페이스 : 프로그래머에게 쉬운 데이터베이스와 연동되는 프로그램을 작성할 수 있게 하는 도구


JDBC 드라이버 : JDBC 인터페이스를 구현하여 실제로 DBMS를 작동시켜서 질의를 던지고 결과를 받습니다.





 JDBC Driver Type 타입의 종류


 JDBC-ODBC 브릿지+ODBC 드라이버

 

네이티브-API 부분적인 자바드라이버


 JDBC-Net 순수 자바 드라이버

 네이티브-프로토콜 

순수 자바 드라이버


JDK에서 제공하는 드라이버로서 

JDBC 뿐만 아니라 ODBC를 같이 이용하여 데이터베이스에 접근하는 방법

 

로컬에 설치된 원시 라이브러리를 

이용해 데이터베이스와 연결되는 방식

어플리케이션이 데이터베이스에 JDBC로 

요청을 하면 이 요청을 

원시 라이브러리의 메소드 호출로 

변환하여 요청을 하는 것입니다.


 타입 2와 비슷하지만 이 방식은 원시 라이브러리의 호출이 

원격 서버에서 이루어지므로 

인터넷에 연결되어져 있다면 

원시 라이브러리를 이용하여 연결되어질 수 있는 이점이 있다.

 순수 자바로 만들어졌음.

ODBC나 원시 라이브러리를 이용하지 

않고 곧바로 데이터베이스에 연결되어진다는 이점이 있음.




-예제 및 출력 결과-


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package ch11;
 
import java.sql.*;
 
public class DriverTest {
    public static void main(String[] args) {
        Connection con;
 
        try {
            Class.forName("org.gjt.mm.mysql.Driver").newInstance(); // org.git.mm.mysql.Driver는 드라이버 이름.
            con = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysql""root""1234"); // 데이터베이스 연결
            System.out.println("Success"); // mysql에서 mydb라는 데이터베이스가 없었기 때문에 mysql 데이터베이스를 대신 연결하였다.
        } catch (SQLException ex) {
            System.out.println("SQLException" + ex );
        } catch (Exception ex) {
            System.out.println("Exception:" + ex );
        }
    }
}
 
cs





-JDBC API-


데이터베이스 연결, 질의 전송, 결과 처리 등의 과정들이 데이터베이스 연동 프로그램시 많이 사용되는 과정들입니다.

이때 쓰이는 인터페이스들은 JDBC API에 존재합니다.


 

  Driver : 모든 드라이버 클래스들이 구현해야 하는 인터페이스 입니다.


  DriverManager : 드라이버를 로드하고 데이터베이스에 연결할 수 있게 됩니다.


  Connection : 특정 데이터베이스와의 연결을 말합니다.


  Statement : SQL문을 실행해 작성된 결과를 돌려줍니다.


  PreparedStatement : 사전에 컴파일 된 SQL문을 실행합니다.


  ResultSet : SQL문에 대한 결과를 얻어냅니다.





-JDBC에서의 한글 처리-


 

  jdbc:mysql://[hostname][:port]/dbname[?param1=value1][&param2=value2]...



위의 구조에서 뒤에 들어갈 파라미터의 종류는 다음과 같습니다.



파라미터 이름


사용 용도

기본 설정값 


user


데이터베이스 사용 user 지정 

none 


password


user의 패스워드 지정 

none


autoReconnect


연결이 해제되었을 때 자동 재연결 설정 여부 

false 


maxReconnects


autoReconnect가 true로 설정되었을 때 재연결까지에 대한 설정 (몇 번의 연결시도를 할 것인지) 


initialTimeout


auto0Reconnect가 true로 설정되었을 때 재연결까지 대기시간 설정(초) 


maxRows

 

반환받는 최대 행 개수 지정(0이면 모든 행을 반환) 


useUnicodde


유니코드 문자 인코딩 사용 여부 지정 

should the driver use Unicode character encodings when handing strings? (true / false) 

false


characterEncoding


useUnicode가 true로 설정되었을 때, 인코딩 종류 지정 

none



MySQL과  Tomcat 연동에 있어서 한글이 깨어지는 것 방지 코드 (JDBC URL에 파라미터를 부여해서 사용)


  ....

  Connection C = DriverManager.getConnection(

                       "jdbc : mysql://localhost/test?useUnicod=true&characterEncoding=EUC-KR");

  ....




-JSP와 데이터베이스 연동-



  JSP에서 JDBC를 통해서 데이터베이스와 연동을 하는 방법 : 데이터베이스에 관련된 프로그램 코드들이 jsp 페이지에 포함되어 있음


  JDBC를 사용해서 데이터베이스에 연결하는 부분을 분리시킨 방법 : jsp 페이지가 아닌 자바빈에 분리시킨 것.

 



-

1. JDBC 드라이버의 인스턴스 생성


 

  Class.forName("Driver_Name");




2. JDBC 드라이버 인스턴스를 통해 DBMS에 대한 연결 설정



  Connection con = DriverManager.getConnection("DBURL", "Account ID", "Account PW");

 



3. Statement 생성



  Statement stmt = conn.createStatement( );

 



4. 질의문 실행/ResultSet으로 결과 받음



  ResultSet rs = stmt.executeQuery("select * from ...");

 



5. ResultSet 해지



  rs.close( );

 



6. Statement 해지



  stmt.close( );

 



7. 데이터베이스와 연결 해지


  

  conn.close( );

 



-예제 및 출력 결과-


데이터베이스 테이블 생성 및 자료 삽입


1
2
3
4
5
6
7
8
9
10
11
12
CREATE TABLE tblRegister(
id VARCHAR(20NOT NULL,
pwd VARCHAR(20NOT NULL,
name CHAR(6NULL,
num1 CHAR(6NULL,
num2 CHAR(7NULL,
email VARCHAR(30NULL,
phone VARCHAR(30NULL,
zipcode CHAR(5NULL,
address VARCHAR(60NULL,
job VARCHAR(30NULL
);
cs



-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
98
99
100
101
102
103
104
105
106
107
<%@ page language="java" contentType="text/html; charset=EUC-KR"
    import="java.sql.*"%>
<%@ page import="java.util.*,ch11.*"%>
<%
    Class.forName("org.gjt.mm.mysql.Driver"); //JDBC 드라이버 인스턴스 생성
    Connection conn = null;
    Statement stmt = null;
    ResultSet rs = null;
 
    String id = "", pwd = "", name = "", num1 = "", num2 = "", email = "", phone = "", zipcode = "",
            address = "", job = "";
    int counter = 0;
    try {
        conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb""root""1234"); //Connection 생성
        stmt = conn.createStatement(); //statement 생성
        rs = stmt.executeQuery("SELECT * FROM tblRegister"); //질의 실행 결과를 ResultSet에 담는다.
%>
<html>
<head>
<title>JSP에서 데이터베이스 연동</title>
<link href="style.css" rel="stylesheet" type="text/css">
<!-- 디자인 관련 (style.css)파일을 링크시킨다. -->
</head>
<body bgcolor="#FFFFCC">
    <h2>JSP 스크립트릿에서 데이터베이스 연동 예제</h2>
    <br />
    <h3>회원정보</h3>
    <table bordercolor="#0000ff" border="1">
        <tr>
            <td><strong>ID</strong></td>
            <td><strong>PWD</strong></td>
            <td><strong>NAME</strong></td>
            <td><strong>NUM1</strong></td>
            <td><strong>NUM2</strong></td>
            <td><strong>EMALL</strong></td>
            <td><strong>PHONE</strong></td>
            <td><strong>ZIPCODE/ADDRESS</strong></td>
            <td><strong>JOB</strong>
        </tr>
        <%
            if (rs != null//질의에 실행 결과가 null값이 아닐때 다음 질의를 실행(slect결과값을 불러옴)
            {
 
                    while (rs.next()) //id등 각종 값을 받아와서 변수에 넣는다.
                    {
                        id = rs.getString("id");
                        pwd = rs.getString("pwd");
                        name = rs.getString("name");
                        num1 = rs.getString("num1");
                        num2 = rs.getString("num2");
                        email = rs.getString("email");
                        phone = rs.getString("phone");
                        zipcode = rs.getString("zipcode");
                        address = rs.getString("address");
                        job = rs.getString("job");
        %>
        <tr>
            <td><%=id%></td>
            <td><%=pwd%></td>
            <td><%=num1%></td>
            <td><%=num2%></td>
            <td><%=email%></td>
            <td><%=phone%></td>
            <td><%=zipcode%></td>
            <td><%=address%></td>
            <td><%=job%></td>
            <%
                counter++//1회전 할때 마다 1씩 증가 전체 출력할 개수를 확인하는 용도
                    } //end while
 
            } //end if
            %>
        </tr>
    </table>
    <br /> total records :
    <%=counter%>
    <%
        } catch (SQLException sqlException) {
            System.out.println("sql exception");
        } catch (Exception exception) {
            System.out.println("exception");
        } finally {
            if (rs != null)
                try {
                    rs.close();
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
 
            if (stmt != null)
                try {
                    stmt.close();
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
 
            if (conn != null)
                try {
                    conn.close();
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
 
        }
    %>
</body>
</html>
cs




-Connection Pool을 사용한 데이터베이스 연결-


사용자가 한꺼번에 많이 몰릴 경우 (트래픽이 많이 걸릴 경우) 요청이 많을 때 서버측은 요청에 맞는 파일 생성을 하고, 필요하면

데이터베이스에 연결해서 자료를 찾고 필요한 자료를 찾은 뒤 데이터베이스 연결을 해제하고, 다시 필요하면 연결하고 끊었다, 

닫았다를 수 없이 되풀이 하게 됩니다.

게다가 데이터베이스에 연결하는 부분은 서버에 많은 부하를 줍니다.

이러한 부하를 줄이기 위해서 데이터베이스에 연결하는 커넥션을 관리하기 위해 커넥션풀을 사용합니다.



  ConnectionPool을 통한 데이터베이스 연결방법



  DBConnectionMgr pool = DBConnectionMgr.getInstance( );   //데이터베이스 연결 풀 객체를 얻습니다.


  conn = pool.getConnection( );  //얻어진 풀로 Connection을 얻는다. 주어진 Connection을 통해서 질의를 던지고 받는 등 업무 처리.


  pool.freeConnection(conn);   //마지막으로 사용된 Connection을 반환합니다. 얻어진 풀 객체를 재사용하기 위해서 닫지 않고 풀에 반환.

 




-데이터베이스 연동 프로그램시 단계-


드라이버 로딩, 커넥션 연결, 질의 전송, 결과 처리의 단계가 있습니다.

하지만 커넥션 풀을 사용하면, 커넥션 풀에서 드라이버 로딩과 커넥션에 대한 관리를 맡아서 해주기 때문에

커넥션 풀을 통해 커넥션을 얻어오기만 합니다.

그리고 나중에 얻어진 커넥션을 다시 풀에 반환합니다.

우선, 풀로부터 커넥션을 얻고 나서 질의를 전송하고, 결과를 받아서 처리를 하는 작업이 행해져야 합니다.

 

 

 

-ConnectionPool과 Bean을 이용한 데이터베이스 연결-

 

데이터베이스 연동관련 코드를 사용하는 프로그램에서 jsp 페이지에 데이터베이스 관련 코드가 있는 것보다 데이터베이스 관련

코드들은 자바빈즈 등의 자바 파일로 분리해서 프로그램을 구현하는 것이 좋습니다.

그리하여 JSP에서는 자바빈을 사용만 하는식의 구성이 좋습니다.

: