본문 바로가기
개발~/JSP

[JSP] 커넥션 풀

by 보배곰 2017. 3. 7.
코드는 SK고용디딤돌 백명숙 강사님 예제 참고
참고한 책: 최범균의 JSP 2.3 웹프로그래밍 기초부터 중급까지(최범균)
chap14. 08 커넥션 풀 415p

개발환경
Eclipse Java EE (version: Neon.3)
Tomcat v8.0
mysql


커넥션 풀이란 데이터베이스와 연결된 커넥션을 미리 만들어서 풀(pool) 속에 저장해 두고 있다가 필요할 때에 커넥션을 풀에서 가져다 쓰고 다시 풀에 반환하는 기법 

커넥션 풀의 특징
    • 풀 속에 미리 커넥션이 생성되어 있기 때문에 커넥션을 생성하는 데 드는 연결 시간을 줄일 수 있다.
    • 커넥션을 계속해서 재사용하기 때문에 생성되는 커넥션 수가 일정하게 유지된다.

DBCP를 이용해서 커넥션 풀 사용하기
    1. DBCP 관련 jar 파일과 JDBC 드라이저 jar 파일 설치하기
    2. 커넥션 풀 초기화하기
    3. 커넥션 풀로부터 커넥션 사용하기

필요한 jar 파일 복사하기
    • Commons DBCP API 관련 jar 파일
    • Commons DBCP API가 사용하는 Commons Pool API의 Jar 파일
    • 로그 기록에 사용하는 Commons Logging API 관련 jar 파일

구글에 commons dbcp jar download, commons pool jar download, commons logging jar download 이런식으로 쳐서 다운 받으면 됩니다~ 


해당 url에서 제일 최신 버전(해당 버전)을 다운.


압축 파일을 풀어서 jar 파일을 WEB-INF/lib에 추가

실제 코드 작성

  1. 커넥션 풀 초기화 서블릿 클래스 작성(DBCPInit.java)

  2. 커넥션 풀 초기화 서블릿 설정(web.xml)

  3. 커넥션 풀로부터 커넥션 사용하기


1. 커넥션 풀 초기화 서블릿 클래스 작성(DBCPInit.java) 

 package t.dao;


 import java.sql.DriverManager;


 import javax.servlet.ServletException;

 import javax.servlet.http.HttpServlet;


 import org.apache.commons.dbcp2.ConnectionFactory;

 import org.apache.commons.dbcp2.DriverManagerConnectionFactory;

 import org.apache.commons.dbcp2.PoolableConnection;

 import org.apache.commons.dbcp2.PoolableConnectionFactory;

 import org.apache.commons.dbcp2.PoolingDriver;

 import org.apache.commons.pool2.impl.GenericObjectPool;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;


public class DBCPInit extends HttpServlet {

private static final long serialVersionUID = 1L;

       

    public DBCPInit() {

        super();

    }

    

    @Override

    public void init() throws ServletException {

    loadJDBCDriver();

    initConnectionPool();

    }


    private void loadJDBCDriver() {

try {

Class.forName("com.mysql.jdbc.Driver").newInstance();

} catch (Exception e) {

e.printStackTrace();

}


System.out.println("after connection.....");

    }


private void initConnectionPool() {

try {

String jdbcUrl = 

"jdbc:mysql://localhost:3306/ajavaprj?" + 

"useUnicode=true&characterEncoding=utf8";

String username = "ajava";

String password = "ajava";

//ConnectionFactory 생성

ConnectionFactory connFactory = new DriverManagerConnectionFactory(jdbcUrl, username, password);

//PoolableConnection을 생성하는 Factory 생성

PoolableConnectionFactory poolableConnFactory = new PoolableConnectionFactory(connFactory, null);

poolableConnFactory.setValidationQuery("select 1");

//커넥션 풀의 설정 정보

GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();

poolConfig.setTimeBetweenEvictionRunsMillis(1000L * 60L * 5L);

poolConfig.setTestWhileIdle(true);

poolConfig.setMinIdle(4);

poolConfig.setMaxTotal(50);

//커넥션 풀 생성 및 연결

GenericObjectPool<PoolableConnection> connectionPool = new GenericObjectPool<>(poolableConnFactory, poolConfig);

poolableConnFactory.setPool(connectionPool);

//커넥션 풀을 제공하는 JDBC 드라이버를 등록

Class.forName("org.apache.commons.dbcp2.PoolingDriver");

//커넥션 풀 드라이버에 생성한 커넥션 풀을 등록

PoolingDriver driver = (PoolingDriver)DriverManager.getDriver("jdbc:apache:commons:dbcp:");

driver.registerPool("broker", connectionPool);

} catch(Exception e) {

System.out.println(e.getMessage());

}

}

}

    1. 현재 제 package는 t.dao 

    2. DB는 Mysql

    3. Mysql Database명은 ajavaprj이고, username과 password는 ajava

    4. 제가 정한 커넥션 풀 이름은 broker

DBCP가 제공하는 PoolingDriver는 커넥션 풀을 위한 JDBC 드라이버이다. PoolingDriver를 통해 커넥션 풀로부터 커넥션을 가져오려면 다음 형식의 JDBC URL을 사용하면 된다. (421p)

jdbc:apache:commons:dbcp:풀이름


2. 커넥션 풀 초기화 서블릿 설정(web.xml)

  <servlet>

  <servlet-name>DBCPInit</servlet-name>

  <servlet-class>t.dao.DBCPInit</servlet-class>

  <load-on-startup>1</load-on-startup>

  </servlet> 

1. servlet-class에 DBCPInit 클래스가 있는 패키지명과, 클래스명을 같이 잘 써주자.

2. web.xml을 수정하면 서버를 다시 내렸다가 올려야 한다. 


web.xml 전체소스


.3 커넥션 풀로부터 커넥션 사용하기

  Connection conn = null;

......

try {

String jdbcUrl = "jdbc:apache:commons:dbcp:broker";

//커넥션 풀에서 커넥션을 구함

conn = DriverManager.getConnection(jdbcUrl);

                .....

} catch(SQLException e) {

System.out.println(e.getMessage());

} finally {

                ...........

//커넥션을 풀에 반환함

try { 

if(conn != null) conn.close();

} catch(SQLException ex) {}

}

그냥 JDBC하는거와 별반 다르지 않음

실제적용) 저는 Database.java라는 따로 클래스가 있고, 여기 생성자에서 db를 연결하고 간단한 로직을 처리합니다.


Database.java

public class Database {

public Connection conn;

public Database() throws SQLException {

// Load the Oracle JDBC Driver

try {

String jdbcUrl = "jdbc:apache:commons:dbcp:broker";

conn = DriverManager.getConnection(jdbcUrl);

System.out.println(conn.getClass().getName());

} catch (Exception e) {

e.printStackTrace();

}


System.out.println("after connection.....");

}

public void close() {

try {

if(conn != null) conn.close();

} catch (SQLException e) {

}

}


public void close(Statement stmt) {

try {

if(stmt != null) stmt.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

        //전체고객조회

public ArrayList<CustomerRec> getAllCustomers() {

System.out.println("getAllCustomers() 들어옴!");

ArrayList<CustomerRec> list = new ArrayList<>();

PreparedStatement stmt = null;

ResultSet rs = null;

String sql = "select * from customer";

try {

stmt = conn.prepareStatement(sql);

rs = stmt.executeQuery();

while(rs.next()) {

list.add(new CustomerRec(rs.getString(1), rs.getString(2), rs.getString(3)));

}

for (CustomerRec customerRec : list) {

System.out.println(customerRec.toString());

}

} catch (SQLException e) {

System.out.println(e.getMessage());

} finally {

close(stmt);

}

return list;

}


index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"

    pageEncoding="UTF-8"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<!DOCTYPE html>

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>index</title>

</head>

<body>

<h2>Broker Customer</h2>

<ul>

<li><a href="${ pageContext.request.contextPath }/BrokerController">Customer 목록 조회</a></li>

</ul>

</body>

</html> 


MyServlet.java

package t.controller;


import java.io.IOException;

import java.sql.SQLException;

import java.util.ArrayList;


import javax.servlet.RequestDispatcher;

import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import t.dao.Database;

import t.vo.CustomerRec;


public class MyServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

Database dao;


protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

try {

dao = new Database();

ArrayList<CustomerRec> custList = dao.getAllCustomers();

request.setAttribute("custList", custList);


RequestDispatcher rd = request.getRequestDispatcher("/customerList.jsp");

rd.forward(request, response);

} catch (SQLException e) {

e.printStackTrace();

}

}


protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

// TODO Auto-generated method stub

doGet(request, response);

}


customerList.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"

    pageEncoding="UTF-8"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<!DOCTYPE html>

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>result</title>

<!-- Latest compiled and minified CSS -->

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">


<!-- Optional theme -->

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">


<!-- Latest compiled and minified JavaScript -->

<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>

</head>

<body>

<div class="container">

<h2>Customer 전체 조회</h2>

<table class="table">

<thead>

<tr>

<th>ssn</th>

<th>name</th>

<th>addr</th>

</tr>

</thead>

<tbody>

<c:forEach var="cust" items="${ custList }">

<tr>

<td>${ cust.ssn }</td>

<td>${ cust.name }</td>

<td>${ cust.addr }</td>

</tr>

</c:forEach>

</tbody>

</table>

</div>

</body>

</html>


전체적인 구조.

원래 Database하나였지만, 커넥션 풀을 위해 DBCPInit 추가함