DBCP(DataBase Connection Pool)

부트캠프(END)/Web|2022. 7. 22. 12:40

데이터베이스를 연동하고, 쿼리를 날려서, 결과를 가져오는 과정은

전체 처리 시간 중에서 꽤 시간을 많이 소요한다.

즉, 효율적으로 데이터베이스와 연결하는 것이 빠른 처리에 영향을 많이 준다!

 

데이터베이스에 연결하는 Connection은 객체 = 새롭게 만들어질 때 시스템의 자원을 요구한다.

 

메모리에 객체를 할당하고, 객체가 사용할 여러 자원들에 대한 초기화 작업을 거친다.

그리고 객체 사용이 끝나면 객체를 다시 회수해야 한다.

→ 품이 많이 듭니다!

 

더군다나 기존의 JDBC는 Connection을 생성한 후 바로 해제되지 않아 메모리 누수가 발생한다.

그렇게 데이터베이스에 연결을 많이 반복할수록 서버에 부하가 가고, 쉽게 서버가 다운된다.

→ Connection 생성을 제한하고 재사용할 수 있도록 해 주도록 기술이 생겨났고, 이것이 DBCP!

 

Connection 객체를 여러 개 만들어 두고 필요할 때마다 가져다 쓰고,

사용이 끝난 객체를 반납하고 또 가져다 사용하는 식으로 작동한다!

또한 미리 데이터베이스에 연결해 두었기 때문에 또 연결하는 시간을 아낄 수 있다.

 

 

그래서 어떻게 쓰는거냐면...

 

Commons DBCP(https://mvnrepository.com/artifact/commons-dbcp/commons-dbcp/1.4)

Commons Pool(https://mvnrepository.com/artifact/commons-pool/commons-pool/1.6)

위 두개의 링크에서 각각의 jar파일 다운로드해서 apache-tomcat-9.0.64\lib 에 두개의 jar파일을 갖다놓는다.


그리고 데이터베이스에 연결해야 하는 프로젝트를 실행시킨 후 

Servers에 있는 server.xml 을 열어 DBCP를 설정해 준다.

 

* Tomcat을 사용한다는 가정 하에 *

아래 정보를 server.xml의 해당 프로젝트 위치의 Context 태그 안에 작성한다.
1. Driver, URL, usename, password
2. auth(=Author, 누가 Connection을 만들어 줄 것인가?)
3. 생성된 Connection을 찾을 수 있게 이름 부여
4. 몇개 생성할지
  maxActive : 동시에 사용할 수 있는 Connection의 최대 개수
  maxIdle : 최대로 유지할 수 있는 Connection
  maxWait : 접속이 늦어질 경우 최대로 기다리는 시간 지정

 

server.xml

 <Context docBase="0722DBCPProject" path="/0722DBCPProject" 
 reloadable="true" source="org.eclipse.jst.jee.server:0722DBCPProject">
       <!-- DBCP 요청하는 부분 -->
      <Resource 
      driverClassName="oracle.jdbc.driver.OracleDriver"
      url="jdbc:oracle:thin:@localhost:1521:XE"
      username="username"
      password="pwd"
      auth="Container"
      name="jdbc/oracle"
      type="javax.sql.DataSource"
      maxActive="10"
      maxIdle="10"
      maxWait="-1"
      />
</Context>

이처럼 server.xml에만 서버 정보가 작성되어 다른 코드에서 서버 정보가 노출되지 않기 때문에 보안에 뛰어나다!

 

그럼 연결한 데이터베이스를 한 번 써 보자.

아래와 같이 서울 여행정보를 이름, 이미지링크, 내용, 주소, 번호 정보를 데이터베이스에서 사용할 것이다.

 

LocationVO.java

package dao;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class LocationVO {
	private int no;
	private String title, poster, msg, address;
}

 

이제 데이터를 받아 와 보자.

JDBC를 쓰는 것과 getConnection() 외에는 동일하다.

DBCP를 이용해서 생성한 연결 객체는 java://comp/env라는 곳에 저장된다.

탐색기를 열어 이름으로 객체를 찾고, 저장된 폴더에서 연결 객체를 읽어 와 사용한다.

 

LocationDAO.java

package dao;
import java.util.*;
import java.sql.*;
import javax.sql.*;
import javax.naming.*;

public class LocationDAO {
  private Connection conn;
  private PreparedStatement ps;
  //DBCP -> POOL(Connection을 저장해서 모아 놓고 관리하는 것)
  //연결 객체 가지고 오기
  public void getConnection() {
    try {
      //저장된 위치를 가지고 온다.(JNDI)-> java://comp/env에 Connection 객체가 저장된다.
      //1. 탐색기를 연다.
      Context init = new InitialContext();
      //2. 드라이버 열기 (lookup = 이름으로 객체를 찾아 오는 것)
      Context c = (Context) init.lookup("java://comp/env");
      //3. 저장된 폴더에서 Connection을 읽어 온다.
      DataSource ds = (DataSource) c.lookup("jdbc/oracle");
      conn = ds.getConnection();
    } catch (Exception ex) {

    }
  }
  //다 쓰고 나서 반환하기(닫기가 아님!!)
  //-> commons-dbcp.jar에서 지원해준다. 다른 사용자가 재사용할 수 있게 해줌.
  public void disConnection() {
    try {
      if (ps != null) ps.close();
      if (conn != null) conn.close();
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }
}

 

LocationDAO.java

웹페이지를 구성할 데이터를 형식에 맞게 가져 오는 기능을 구현한다.

package dao;
import java.util.*;
import java.sql.*;
import javax.sql.*;
import javax.naming.*;

public class LocationDAO {
  //기능 구현
  public List < LocationVO > locationListData(int page) {
    List < LocationVO > list = new ArrayList < LocationVO > ();
    try {
      getConnection(); //미리 생성된 Connection 객체 주소를 얻어 온다
      String sql = "SELECT no, title, poster, num " +
        "FROM (SELECT no, title, poster, rownum as num " +
        "FROM (SELECT no, title, poster " +
        "FROM seoul_location ORDER BY no ASC)) " +
        "WHERE num BETWEEN ? AND ?";
      //rownum을 이용하면 Top-N만 가능하고 중간에서 잘라올 수 없다.
      ps = conn.prepareStatement(sql);
      int rowSize = 12;
      int start = (rowSize * page) - (rowSize - 1);
      int end = rowSize * page;
      ps.setInt(1, start);
      ps.setInt(2, end);

      ResultSet rs = ps.executeQuery();
      while (rs.next()) {
        LocationVO vo = new LocationVO();
        vo.setNo(rs.getInt(1));
        vo.setTitle(rs.getString(2));
        vo.setPoster(rs.getString(3));
        list.add(vo);
      }
    } catch (Exception ex) {

    } finally {
      disConnection();
    }
    return list;
  }

  //총 페이지 구하기
  public int locationTotalPage() {
    int total = 0;
    try {
      getConnection();
      String sql = "SELECT CEIL(COUNT(*)/12.0) " +
        "FROM seoul_location";
      ps = conn.prepareStatement(sql);
      ResultSet rs = ps.executeQuery();
      rs.next();
      total = rs.getInt(1);
      rs.close();
    } catch (Exception ex) {
      ex.printStackTrace();
    } finally {
      disConnection();
    }
    return total;
  }

 

그리고 페이지를 아래와 같이 구성하면... 

 

seoul.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="java.util.*, dao.*"%>
<jsp:useBean id="dao" class="dao.LocationDAO"/>
<%
	//1. page받기
	String strPage = request.getParameter("page");
	if(strPage==null)
		strPage = "1";
	int curPage = Integer.parseInt(strPage);
	//현재 페이지에 해당되는 데이터 읽어 오기
	List<LocationVO> list = dao.locationListData(curPage);
	//총페이지 구하기
	int totalPage = dao.locationTotalPage();
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<style type="text/css">
	.container{
	  margin-top:50px;
	}
	.row{
	  margin: 0px auto;
	  width: 960px;
	}
</style>
</head>
<body>
  <div class="container">
    <div class="row">
    <%
    	for(LocationVO vo:list){
    %>
      <div class="col-md-3">
      <div class="thumbnail">
        <a href="#">
          <img src="<%=vo.getPoster() %>" alt="" style="width:220px; height:150px">
          <div class="caption">
            <p style="font-size:9px"><%=vo.getTitle() %></p>
          </div>
        </a>
      </div>
    </div>
    <%}%>
    </div>
    <div class="row">
    	<div class="text-center">
    		<a href="seoul.jsp?page=<%=curPage>1?curPage-1:curPage %>" class="btn btn-sm btn-success">이전</a>
    		<%=curPage %>page/<%=totalPage %>pages
    		<a href="seoul.jsp?page=<%=curPage<totalPage?curPage+1:curPage %>" class="btn btn-sm  btn-info">다음</a>
    	</div>
    </div>
  </div>
</body>
</html>

 

짜잔! 이렇게 된다~

 

 

Reference : 

https://d2.naver.com/helloworld/5102792

'부트캠프(END) > Web' 카테고리의 다른 글

EL/JSTL  (0) 2022.07.25
JSP : 내장 객체 / session  (0) 2022.07.21
jspBean  (0) 2022.07.21

댓글()