[JSP] Connection Pool

Junseo Kim·2020년 1월 15일
4

[JSP]JSP기초

목록 보기
16/19

Connection Pool이란?

DB를 다룰 때, 사용한 connection 객체, Statement 객체 같은 자원들을 효율적으로 사용하기 위한 방법이다.

웹 서버가 DB에 접속해야할 때, 너무 많은 요청이 있을 경우 과부하가 있을 수 있다. 그래서 매번 해야하는 작업인 connection을 미리 만들어놓고 필요할 때마다 가져다 쓰는 것이다.

connection pool은 톰캣 컨테이너에 미리미리 만들어 놓고, 필요할 때마다 빌려서 사용하고 반환해주는 것이다.

Connection Pool 설정

먼저 File - Project Structure에 들어간다.

스크린샷 2020-01-16 오전 12.32.24.png

Modules 탭을 누른 후, web을 선택하고, Add Application Server specific descripter(빨간 네모 부분)를 클릭한다.

스크린샷 2020-01-16 오전 12.33.01.png

Tomcat server를 선택해준다.

스크린샷 2020-01-16 오전 12.33.26.png

Ok를 누르면 web - META-INF 하위에 context.xml이 생긴것을 볼 수 있다.

스크린샷 2020-01-16 오전 12.38.46.png

context.xml에 아래와 같은 코드를 넣어준다.

  • auth: 인증하는 부분. 이 톰캣 컨테이너를 connection pool로 사용하겠다고 명시해주는 부분.
  • dricerClassName: driver 패키지 이름
  • url: db경로
  • username: db id
  • password: db 비밀번호
  • name: connection pool의 이름(임의로 해도 되지만 보통 'jdbc/db의 이름'으로 많이 해준다. 자바에서 connection pool을 사용할 때 이 name 값을 통해 호출
  • type: connection을 만들어주는 객체. API.
  • maxActive: connection pool을 미리 만들어 놓을 갯수. 만약 4로 설정해놓고 전부 소모한 다음 요청이 또 들어와도 에러는 나지 않고, 컨테이너가 알아서 하나를 더 만들어준다.
  • maxWait: 컨테이너가 자동으로 connection pool을 생성할 때 기다리는 시간. 이 시간동안 기다려도 resource가 부족하여 새로 생성 못할 시는 에러 발생

스크린샷 2020-01-16 오전 12.45.22.png

이렇게 설정 해놓으면, 자바코드에서 더이상 connection을 만들 필요가 없다.(이전에 DAO와 DTO를 사용했던 코드를 connection pool을 사용한 코드로 변경해보겠다.)

BookDAO.java 파일에서 커넥션 풀을 담기 위한 DataSource 타입의 변수를 선언해준다.

스크린샷 2020-01-16 오전 1.30.00.png

Context를 생성 후, lookup 메서드를 이용하여, context.xml에서 설정해준 connection pool의 이름으로 connection pool을 받아온다.

스크린샷 2020-01-16 오전 1.28.34.png

select 메서드에서 직접 Connection 객체를 생성하는 대신, 가져온 connection pool(dataSource)의 getConnection 메서드를 사용하여 Connection 객체를 가져온다.

스크린샷 2020-01-16 오전 1.28.47.png

connection pool을 사용했다 하더라도, 자원 해제는 똑같이 해주어야한다.

스크린샷 2020-01-16 오전 1.29.07.png

실행 시켜보면 정상작동함을 알 수 있다.

스크린샷 2020-01-16 오전 1.33.32.png

*만약 실행 시cannot be cast to class com.mysql.jdbc.Connection 에러가 나면 import가 잘못된 것이다. [import com.mysql.jdbc.Connection;] -> [import java.sql.Connection;] 로 바꿔준다.

전체코드

BookServlet.java와 BookDTO.java는 여기(https://velog.io/@max9106/JSP-DAO-DTO-tnk5eba5tu) 코드와 동일하다.

context.xml

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/">
    <Resource
        auth = "Container"
        driverClassName = "com.mysql.jdbc.Driver"
        url = "jdbc:mysql://localhost/[db이름]"
        username = "[mysql id]"
        password = "[mysql password]"
        name = "[connection pool 이름]"
        type="javax.sql.DataSource"
        maxActive = "4"
        maxWait = "10000"
        />
</Context>
BookDAO.java

package com.servlet.dao;

import java.sql.Connection;
import com.servlet.dto.BookDTO;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;

public class BookDAO {

    // 얻어온 커넥션 풀을 받아오기 위함
    DataSource dataSource;

    // BookDAO가 생성되면서 같이 드라이버도 메모리에 올라갈 수 있도록 생성자에 코딩
    public BookDAO() {
        try{
            // Connection Pool을 찾는 과정
            Context context = new InitialContext(); // context 생
            dataSource = (DataSource)context.lookup("java:comp/env/jdbc/Mysql"); // context.xml에서 설정해준 Resource의 name부분

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 실제로 DB에 접근하여 데이터를 가져오는 역할을 하는 메서드
    public ArrayList<BookDTO> select() {
        ArrayList<BookDTO> list = new ArrayList<BookDTO>();

        // 연결을 위한 Connection 객체
        Connection con = null;
        // 통신하기 위한 PreparedStatement 객체
        PreparedStatement pstmt = null;
        // select 결과 값을 담기 위한 ResultSet 객체
        ResultSet res = null;

        // 실제로 DB에 접근하는 부분
        try{
            // dataSource로 부터 connection을 가져옴
            con = dataSource.getConnection();
            String sql = "SELECT * FROM book"; // query
            pstmt = con.prepareStatement(sql); // preparedStatement
            res = pstmt.executeQuery(); // run

            while(res.next()){
                int bookId = res.getInt("book_id");
                String bookName = res.getString("book_name");
                String bookLoc = res.getString("book_loc");

                BookDTO bookDTO = new BookDTO(bookId, bookName, bookLoc); // DTO 객체에 DB에서 읽어온 값 넣어서 호출
                list.add(bookDTO); // arraylist에 생성된 DTO객체 넣어줌
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally { // 자원 해제는 똑같이 해주어야 한다.
            try {
                if(res != null) res.close();
                if(pstmt != null) pstmt.close();
                if(con != null) con.close();
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        return list;
    }
}

0개의 댓글