WEB/Java BackEnd

[WEB] DBcpBean(DataBase Connection Pool Bean)

Happyoon ~ 2021. 11. 24. 14:11
728x90
반응형

웹페이지 서비스 시에 가장 많은 시간이 소요되는 부분이 "데이터베이스를 로드하고 연결"하는 부분이다.

따라서, 미리 만들어놨다가 필요할 때 저장소에서 가져다 쓰고 다시 반납하는 "커넥션풀"을 사용할 필요가 있다.

그동안 DB를 쓰면서 Dao등을 사용할 때 항상 new 해서 객체를 새로 생성하여 사용했었는데, Dao 객체를 하나 만들어놓고 이 하나의 객체를 필요 시에 쓰고 다시 반납하는 구조를 사용하면 웹 서비스 시간을 줄일 수 있다.

따라서, Connection 객체를 얻어와 리턴해주는 DBcpBean 클래스를 만들어보자.

 

DbcpBean 클래스는 Java Resources 에 만든다.


DbcpBean.java

package test.util;

import java.sql.Connection;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;

public class DbcpBean {
   //필드
   private Connection conn;
   //생성자
   public DbcpBean() {
      try {
         Context initContext = new InitialContext();
         Context envContext  = (Context)initContext.lookup("java:/comp/env");
         DataSource ds = (DataSource)envContext.lookup("jdbc/myoracle");
         //얻어온 Connection 객체의 참조값을 필드에 저장한다.
         conn = ds.getConnection();
      }catch(Exception e) {
         e.printStackTrace();
      }
   }
   //Connection 객체를 리턴해주는 메소드
   public Connection getConn() {
      return conn;
   }
}

 


위의 클래스가 동작하려면 다음의 설정들이 필요하다.

 

1. Servers/context.xml 문서에 DB 접속 정보가 있어야 한다.

<Resource name="jdbc/myoracle" auth="Container"
              type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver"
              url="jdbc:oracle:thin:@127.0.0.1:1521:xe"
              username="scott" password="tiger" maxTotal="20" maxIdle="10"
              maxWaitMillis="-1"/>

 

 

2. 프로젝트의 WEB-INF/web.xml 문서에 아래의 설정이 있어야 한다.

 <resource-ref>
      <description>Oracle Datasource example</description>
      <res-ref-name>jdbc/myoracle</res-ref-name>
      <res-type>javax.sql.DataSource</res-type>
      <res-auth>Container</res-auth>
   </resource-ref>

 

3. WEB-INF/lib/ 폴더에 ojdbc6.jar 파일을 넣어서 라이브러리를 사용할 준비를 해야한다.

 

위의 3가지 설정을 한후에 
   
   - new DbcpBean().getConn() 메소드를 호출하면 Connection Pool 에서 Connection 객체가 하나 리턴된다. 
   
   - Dao 에서 Connection 객체를 사용한후 .close() 메소드를 호출하면 자동으로 Connection Pool 에 Connection 객체가 반환된다.


CompanyDao 를 DbcpBean을 활용해 작성해보자.

CompanyDao.java

package test.company.dao;

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

import test.company.dto.CompanyDto;
import test.util.DbcpBean;

public class CompanyDao {
	
	private static CompanyDao dao;
	
	private CompanyDao() {}
	
	public static CompanyDao getInstance() {
		if(dao==null) {
			dao=new CompanyDao();
		}
		return dao;
	}
	
	//사원 한명의 정보를 추가하는 메소드
	public boolean insert(CompanyDto dto) {
		//필요한 객체를 담을 지역 변수 미리 만들기
		Connection conn = null;
		PreparedStatement pstmt = null;
		int flag = 0;
		try {
			//Connection 객체의 참조값 얻어오기 
			conn = new DbcpBean().getConn();
			//실행할 sql 문의 뼈대 미리 준비하기
			String sql = "insert into company"
					+ " (empno,ename,job,hiredate)"
					+ " values(company_seq.nextval,?,?,sysdate)";
			//PreparedStatement 객체의 참조값 얻어오기
			pstmt = conn.prepareStatement(sql);
			//? 에 필요한값 바인딩하기 
			pstmt.setString(1,dto.getEname());
			pstmt.setString(2,dto.getJob());
			//sql 문 실행하기 (INSERT, UPDATE, DELETE)
			flag = pstmt.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (pstmt != null)
					pstmt.close();
				if (conn != null)
					conn.close();
			} catch (SQLException e) {
			}
		}
		if (flag > 0) {
			//성공
			return true;
		} else {
			//실패
			return false;
		}
	}
	//사원 한명의 정보를 수정하는 메소드
	public boolean update(CompanyDto dto) {
		//필요한 객체를 담을 지역 변수 미리 만들기
		Connection conn = null;
		PreparedStatement pstmt = null;
		int flag = 0;
		try {
			//Connection 객체의 참조값 얻어오기 
			conn = new DbcpBean().getConn();
			//실행할 sql 문의 뼈대 미리 준비하기
			String sql = "update company"
					+ " set ename=?,job=?"
					+ " where empno=?";
			//PreparedStatement 객체의 참조값 얻어오기
			pstmt = conn.prepareStatement(sql);
			//? 에 필요한값 바인딩하기 
			pstmt.setString(1,dto.getEname());
			pstmt.setString(2,dto.getJob());
			pstmt.setInt(3,dto.getEmpno());
			//sql 문 실행하기 (INSERT, UPDATE, DELETE)
			flag = pstmt.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (pstmt != null)
					pstmt.close();
				if (conn != null)
					conn.close();
			} catch (SQLException e) {
			}
		}
		if (flag > 0) {
			//성공
			return true;
		} else {
			//실패
			return false;
		}
	}
	//사원 한명의 정보를 삭제하는 메소드
	public boolean delete(int num) {
		//필요한 객체를 담을 지역 변수 미리 만들기
		Connection conn = null;
		PreparedStatement pstmt = null;
		int flag = 0;
		try {
			//Connection 객체의 참조값 얻어오기 
			conn = new DbcpBean().getConn();
			//실행할 sql 문의 뼈대 미리 준비하기
			String sql = "delete from company"
					+ " where empno=?";
			//PreparedStatement 객체의 참조값 얻어오기
			pstmt = conn.prepareStatement(sql);
			//? 에 필요한값 바인딩하기 
			pstmt.setInt(1,num);
			//sql 문 실행하기 (INSERT, UPDATE, DELETE)
			flag = pstmt.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (pstmt != null)
					pstmt.close();
				if (conn != null)
					conn.close();
			} catch (SQLException e) {
			}
		}
		if (flag > 0) {
			//성공
			return true;
		} else {
			//실패
			return false;
		}
	}
	//사원 한명의 정보를 리턴하는 메소드
	public CompanyDto getData(int empno) {
		//필요한 객체를 담을 지역 변수 미리 만들기
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		CompanyDto dto=null;
		try {
			//Connection 객체의 참조값 얻어오기 
			conn = new DbcpBean().getConn();
			//실행할 sql 문의 뼈대 미리 준비하기
			String sql = "select ename,job,hiredate"
					+ " from company"
					+ " where empno=?";
			//PreparedStatement 객체의 참조값 얻어오기
			pstmt = conn.prepareStatement(sql);
			//? 에 필요한값 바인딩하기 
			pstmt.setInt(1, empno);
			//select 문 수행하고 결과를 ResultSet 으로 받아오기 
			rs = pstmt.executeQuery();
			if (rs.next()) {
				//cursor 가 위치한 곳의 칼럼 데이터를 빼오기 
				dto=new CompanyDto();
				dto.setEmpno(empno);
				dto.setEname(rs.getString("ename"));
				dto.setJob(rs.getString("job"));
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (rs != null)
					rs.close();
				if (pstmt != null)
					pstmt.close();
				if (conn != null)
					conn.close();
			} catch (SQLException e) {}
		}
		return dto;
	}
	//사원 전체 목록을 리턴하는 메소드
	public List<CompanyDto> getList(){
		//필요한 객체를 담을 지역 변수 미리 만들기
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		List<CompanyDto> list=new ArrayList<>();
		try {
			//Connection 객체의 참조값 얻어오기 
			conn = new DbcpBean().getConn();
			//실행할 sql 문의 뼈대 미리 준비하기
			String sql = "select empno,ename,job,hiredate"
					+ " from company"
					+ " order by empno asc";
			//PreparedStatement 객체의 참조값 얻어오기
			pstmt = conn.prepareStatement(sql);
			//? 에 필요한값 바인딩하기 

			//select 문 수행하고 결과를 ResultSet 으로 받아오기 
			rs = pstmt.executeQuery();
			while (rs.next()) {
				//cursor 가 위치한 곳의 칼럼 데이터를 빼오기 
				CompanyDto dto=new CompanyDto();
				dto.setEmpno(rs.getInt("empno"));
				dto.setEname(rs.getString("ename"));
				dto.setJob(rs.getString("job"));
				dto.setHiredate(rs.getString("hiredate"));
				
				list.add(dto);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (rs != null)
					rs.close();
				if (pstmt != null)
					pstmt.close();
				if (conn != null)
					conn.close();
			} catch (SQLException e) {
			}
		}
		return list;
	}
	
}

생성자는 private으로 설정하고, getInstance()를 사용한다.

getInstance() 메소드는 dao가 null일때는 최초이므로, CompanyDao() 객체를 생성하여 dao를 반환하고, null이 아닌 경우에는 dao를 반환한다.

여기서 Instance란 참조값이라는 뜻이다. 

dao가 하나이므로 싱글톤이므로 static으로 작성하고, Companydao.getInstance()로 호출할 수 있다.

 

 

Connection Pool을 그림으로 표현하면 다음과 같다.

getInstance() 호출 모습 

반응형