DB를 다룰 때, 사용한 connection 객체, Statement 객체 같은 자원들을 효율적으로 사용하기 위한 방법이다.
웹 서버가 DB에 접속해야할 때, 너무 많은 요청이 있을 경우 과부하가 있을 수 있다. 그래서 매번 해야하는 작업인 connection을 미리 만들어놓고 필요할 때마다 가져다 쓰는 것이다.
connection pool은 톰캣 컨테이너에 미리미리 만들어 놓고, 필요할 때마다 빌려서 사용하고 반환해주는 것이다.
먼저 File - Project Structure에 들어간다.
Modules 탭을 누른 후, web을 선택하고, Add Application Server specific descripter(빨간 네모 부분)를 클릭한다.
Tomcat server를 선택해준다.
Ok를 누르면 web - META-INF 하위에 context.xml이 생긴것을 볼 수 있다.
context.xml에 아래와 같은 코드를 넣어준다.
이렇게 설정 해놓으면, 자바코드에서 더이상 connection을 만들 필요가 없다.(이전에 DAO와 DTO를 사용했던 코드를 connection pool을 사용한 코드로 변경해보겠다.)
BookDAO.java 파일에서 커넥션 풀을 담기 위한 DataSource 타입의 변수를 선언해준다.
Context를 생성 후, lookup 메서드를 이용하여, context.xml에서 설정해준 connection pool의 이름으로 connection pool을 받아온다.
select 메서드에서 직접 Connection 객체를 생성하는 대신, 가져온 connection pool(dataSource)의 getConnection 메서드를 사용하여 Connection 객체를 가져온다.
connection pool을 사용했다 하더라도, 자원 해제는 똑같이 해주어야한다.
실행 시켜보면 정상작동함을 알 수 있다.
*만약 실행 시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;
}
}