Connection Pool

jinkyung·2021년 1월 21일
0

JSP

목록 보기
13/20

싱글 커넥션

: 같은 커넥션을 이용하는 DAO들의 작업에 영향을 준다.
하나의 connection 객체(contextListener)를 공유하면 예외발생시 문제의 소지가 있다.
하나에서 rollback 했는데 다른 dao들에게까지 영향을 미칠 수 있다.


해결책은 무엇일까?
-> 쓸 때마다 생성하는 것은 낭비이다.



Connection Pool

: 미리 여러개를 만들어놓고 돌아가면서 쓸 수 있도록 하는 방식.
빌려주고 반납하는 방식!
미리 만들어 놓는 것과 필요할 때마다 만드는 것은 속도차이가 많이 난다.
미리 만들어놓은 것이므로 속도 저하가 발생하지 않는다.


DBConnectionPool.java

package spms.util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.util.ArrayList;

public class DBConnectionPool {
	final int PRE_POOL_SIZE = 10;
	String url;
	String username;
	String password;
	ArrayList<Connection> connList = new ArrayList<Connection>();
	
	public DBConnectionPool(String driver, String url,
					String username, String password) throws Exception{
		this.url = url;
		this.username = username;
		this.password = password;
		
		Class.forName(driver);
		
		//미리 pool size만큼(10개) 만들어놓기 
		for(int i=0; i<PRE_POOL_SIZE; i++) {
			connList.add(DriverManager.getConnection(url, username, password));
		}
	}
	
	// Connection 객체를 요청하면 대여해줌
	public Connection getConnection() throws Exception{
		// 현재 저장된 여유분이 존재한다면
		if(connList.size() > 0) {
			// 1번째 Connection객체를 꺼낸다
			//remove는 remove된 객체를 반환한다 
			Connection conn = connList.remove(0);
			
//			DBMS는 일정시간 아무 요청이 없는 경우 timeout에 의해 연결이 해제된다.
//			그러므로 확인을 해야한다.
			// Connection객체가 DB와 연결되어 있다면
			if(conn.isValid(10)) {
				// 꺼낸 것을 리턴한다
				return conn;
			}
		}
		
		//여유분이 없으면 새로 연결해서 리턴한다 
		return DriverManager.getConnection(url, username, password);
	}
	
	//빌려서 사용하고 다 사용했으면 Connection 객체를 반납한다 
	public void returnConnection(Connection conn) throws Exception{
		if(conn != null && conn.isClosed()==false) {
			connList.add(conn);
		}
	}
	
	//종료시 모든 Connection 객체 닫기
	public void closeAll() {
		for(Connection conn : connList) {
			try {
				conn.close();
			}catch(Exception e) {
				e.printStackTrace();
			}
		}
	}
}

MemberDao.java

package spms.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import spms.util.DBConnectionPool;
import spms.vo.Member;

public class MemberDao {

	DBConnectionPool connPool;

	public void setDBConnectionPool(DBConnectionPool connPool) {
		this.connPool = connPool;
	}

	public List<Member> selectList() throws Exception {
		Connection connection = null;
		Statement stmt = null;
		ResultSet rs = null;
		final String sqlSelect = "SELECT mno,mname,email,cre_date" + "\r\n" + "FROM members" + "\r\n"
				+ "ORDER BY mno ASC";

		try {
			// 커넥션풀에서 Connection객체를 빌려온다
			connection = connPool.getConnection();

			stmt = connection.createStatement();
			rs = stmt.executeQuery(sqlSelect);

			ArrayList<Member> members = new ArrayList<Member>();

			while (rs.next()) {
				members.add(new Member().setNo(rs.getInt("mno")).setName(rs.getString("mname"))
						.setEmail(rs.getString("email")).setCreatedDate(rs.getDate("cre_date")));
			}

			return members;

		} catch (Exception e) {
			throw e;
		} finally {
			try {
				if (rs != null)
					rs.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			try {
				if (stmt != null)
					stmt.close();
			} catch (Exception e) {
				e.printStackTrace();
			}

			// 다 썼으면 반납하자
			connPool.returnConnection(connection);
		}
	}

	public int insert(Member member) throws Exception {
		Connection connection = null;
		int result = 0;
		PreparedStatement stmt = null;
		final String sqlInsert = "INSERT INTO members(email,pwd," + "\r\n" + "mname,cre_date,mod_date)" + "\r\n"
				+ "VALUES(?, ?, ?, NOW(), NOW())";

		try {
			// 커넥션풀에서 Connection객체를 빌려온다
			connection = connPool.getConnection();

			stmt = connection.prepareStatement(sqlInsert);
			stmt.setString(1, member.getEmail());
			stmt.setString(2, member.getPassword());
			stmt.setString(3, member.getName());
			result = stmt.executeUpdate();
		} catch (Exception e) {
			throw e;
		} finally {
			try {
				if (stmt != null)
					stmt.close();
			} catch (Exception e) {
				e.printStackTrace();
			}

			// 다 썼으면 반납하자
			connPool.returnConnection(connection);
		}

		return result;
	}

	public int delete(int no) throws Exception {
		Connection connection = null;
		int result = 0;
		Statement stmt = null;
		final String sqlDelete = "DELETE FROM MEMBERS WHERE MNO=";

		try {
			// 커넥션풀에서 Connection객체를 빌려온다
			connection = connPool.getConnection();

			stmt = connection.createStatement();
			result = stmt.executeUpdate(sqlDelete + no);

		} catch (Exception e) {
			throw e;

		} finally {
			try {
				if (stmt != null)
					stmt.close();
			} catch (Exception e) {
				e.printStackTrace();
			}

			// 다 썼으면 반납하자
			connPool.returnConnection(connection);
		}

		return result;
	}

	public Member selectOne(int no) throws Exception {
		Connection connection = null;
		Member member = null;
		Statement stmt = null;
		ResultSet rs = null;

		final String sqlSelectOne = "SELECT MNO,EMAIL,MNAME,CRE_DATE FROM MEMBERS" + " WHERE MNO=";

		try {
			// 커넥션풀에서 Connection객체를 빌려온다
			connection = connPool.getConnection();
			stmt = connection.createStatement();
			rs = stmt.executeQuery(sqlSelectOne + no);
			if (rs.next()) {
				member = new Member().setNo(rs.getInt("MNO")).setEmail(rs.getString("EMAIL"))
						.setName(rs.getString("MNAME")).setCreatedDate(rs.getDate("CRE_DATE"));

			} else {
				throw new Exception("해당 번호의 회원을 찾을 수 없습니다.");
			}

		} catch (Exception e) {
			throw e;
		} finally {
			try {
				if (rs != null)
					rs.close();
			} catch (Exception e) {
			}
			try {
				if (stmt != null)
					stmt.close();
			} catch (Exception e) {
			}

			// 다 썼으면 반납하자
			connPool.returnConnection(connection);
		}

		return member;
	}

	public int update(Member member) throws Exception {
		Connection connection = null;
		int result = 0;
		PreparedStatement stmt = null;
		final String sqlUpdate = "UPDATE MEMBERS SET EMAIL=?,MNAME=?,MOD_DATE=now()" + " WHERE MNO=?";
		try {
			// 커넥션풀에서 Connection객체를 빌려온다
			connection = connPool.getConnection();
			stmt = connection.prepareStatement(sqlUpdate);
			stmt.setString(1, member.getEmail());
			stmt.setString(2, member.getName());
			stmt.setInt(3, member.getNo());
			result = stmt.executeUpdate();

		} catch (Exception e) {
			throw e;
		} finally {
			try {
				if (stmt != null)
					stmt.close();
			} catch (Exception e) {
			}

			// 다 썼으면 반납하자
			connPool.returnConnection(connection);
		}

		return result;
	}

	public Member exist(String email, String password) throws Exception {
		Connection connection = null;
		Member member = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		final String sqlExist = "SELECT MNAME,EMAIL FROM MEMBERS" + " WHERE EMAIL=? AND PWD=?";

		try {
			// 커넥션풀에서 Connection객체를 빌려온다
			connection = connPool.getConnection();
			
			stmt = connection.prepareStatement(sqlExist);
			stmt.setString(1, email);
			stmt.setString(2, password);
			rs = stmt.executeQuery();
			if (rs.next()) {
				member = new Member().setName(rs.getString("MNAME")).setEmail(rs.getString("EMAIL"));
			} else {
				return null;
			}
		} catch (Exception e) {
			throw e;

		} finally {
			try {
				if (rs != null)
					rs.close();
			} catch (Exception e) {
			}
			try {
				if (stmt != null)
					stmt.close();
			} catch (Exception e) {
			}

			// 다 썼으면 반납하자
			connPool.returnConnection(connection);
		}

		return member;
	}
}

ContextLoaderListener

package spms.listeners;

import java.sql.Connection;
import java.sql.DriverManager;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import spms.dao.MemberDao;
import spms.util.DBConnectionPool;

public class ContextLoaderListener implements ServletContextListener {	
	DBConnectionPool connPool;
	
	@Override
	public void contextDestroyed(ServletContextEvent sce) {
		try {
			System.out.println("contextDestroyed");
			
			//웹 어플리케이션이 종료시 모든 Connection 객체를 닫는다 
			connPool.closeAll();
		}catch(Exception e) {
			e.printStackTrace();
		}

	}

	@Override
	public void contextInitialized(ServletContextEvent sce) {
		try {
			System.out.println("contextInitialized");
			ServletContext sc = sce.getServletContext();

			connPool = new DBConnectionPool(
					sc.getInitParameter("driver"),
					sc.getInitParameter("url"),
					sc.getInitParameter("username"),
					sc.getInitParameter("password"));
			
			
			//dao 객체를 만들었고 dao객체 필드영역인 conn에 db를 연결했다.
			MemberDao memberDao = new MemberDao();
			memberDao.setDBConnectionPool(connPool);
			
			//conn객체 대신 memberDao 객체를 공유 
			sc.setAttribute("memberDao", memberDao);
											
		}catch(Exception e) {
			e.printStackTrace();
		}
		
		
		
	}

}

ContextLoaderListener에서 driver, url, id, pwd를 가져와서 memberDao에 심어준다. 서블릿에서는 dao를 활용해서 db에 연결이 가능한 것이다.

0개의 댓글