[JSP] jsp 홈페이지 만들기 (4) : 클라이언트 구분하기

·2023년 10월 31일
0

jsp

목록 보기
5/18

2. 클라이언트 구분하기

(1) Connection 객체 생성하기

package my.db;
import java.sql.*;
import java.util.*;
public class ConnectionPoolBean {
	private String url, user, pass;
	private Hashtable<Connection, Boolean> ht;
	private int increment;

	
	public ConnectionPoolBean() throws ClassNotFoundException, SQLException {
		increment = 3;		// 필요한 경우 세 개씩 증가시킨다.
		ht = new Hashtable<Connection, Boolean>(5);
		url = "jdbc:oracle:thin:@localhost:1521:xe";
		user = "fin01";
		pass = "fin01";
		Class.forName("oracle.jdbc.driver.OracleDriver");
		
		for(int i=0; i<5; ++i){
			Connection con = DriverManager.getConnection(url, user, pass);
			ht.put(con, Boolean.FALSE);
			// 클라이언트가 사용하지 않는다면 - false 이므로
		}
	}
	
	public synchronized Connection getConnection() throws SQLException {
		Enumeration<Connection> enkey = ht.keys();
		Connection con = null;
		while(enkey.hasMoreElements()){
			con = enkey.nextElement();
			Boolean b = ht.get(con);
			if (b == Boolean.FALSE){
				ht.put(con, Boolean.TRUE);
				return con;
			}
		}
		
		// 꽉 찼다면 increment로 Connection 객체 늘려 주기
		for(int i=0; i<increment; ++i){
			Connection con2 = DriverManager.getConnection(url, user, pass);
			ht.put(con2, Boolean.FALSE);
		}
		return getConnection();
	}
	
	public void returnConnection(Connection returnCon) throws SQLException{
		Connection con = null;
		Enumeration<Connection> enkey = ht.keys();
		while(enkey.hasMoreElements()){
			con = enkey.nextElement();
			if (returnCon == con) {
				ht.put(con, Boolean.FALSE);
				break;
			}
		}
		removeCon();
	}
	
	public void removeCon() throws SQLException {
		int count = 0;
		Connection con = null;
		Enumeration<Connection> enkey = ht.keys();
		while(enkey.hasMoreElements()){
			con = enkey.nextElement();
			Boolean b = ht.get(con);
			if(b == Boolean.FALSE){
				count++;
				if(count>5){
					ht.remove(con);
					con.close();
					// 내보낸 애를 close 해야 없어지는 거임!
				}
			}
		}
	}
	
	public void closeAll() throws SQLException {
		Connection con = null;
		Enumeration<Connection> enkey = ht.keys();
		while(enkey.hasMoreElements()){
			con = enkey.nextElement();
			con.close();
		}
	}
}

위 코드는 미리 connection 객체를 생성해 놓고 필요한 클라이언트에게 주고 클라이언트는 사용 후 반납하는 방식이다. 이러면 클라이언트가 사용할 때마다 객체를 생성할 필요가 없기 때문에 적당량, 적정량을 빠른 시간 내에 사용할 수 있다. Connection을 만들어 놓고 사용하는 풀장이라 poolBean이라고 한다. Bean은 객체를 말한다.

(2) DAO 수정해 주기

그럼 con 객체를 생성해서 관리하는 것으로 바뀌었으니까 이제 DAO에 있는 con 변수는 pool 값을 넣어 주어야 한다. 모든 DAO를 수정해야 하지만 수정해야 하는 부분만을 짚자면

- 생성자에 con 삭제 가능

	public StudentDAO() {	
		/* 
	
		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
		}catch(ClassNotFoundException e) {
			e.printStackTrace();
		}
		
		url = "jdbc:oracle:thin:@localhost:1521:xe";
		user = "fin01";
		pass = "fin01";
		*/
	}

드라이버를 연결해 주려고 사용했던 생성자의 기능들은 이제 pool 객체가 알아서 하므로 삭제 가능하다.

- 각 메서드 수정해 주기

	public int insertStudent(StudentDTO dto) throws SQLException {
		try {
			Connection con = pool.getConnection();
			String sql = "insert into student values(?, ?, ?)";
			PreparedStatement ps = con.prepareStatement(sql);
			ps.setString(1, dto.getId());
			ps.setString(2, dto.getName());
			ps.setString(3, dto.getCname());
			// insert delete update => executeUpdate();		 : 반환형 int
			// select => executeQuery();					 : 반환형 ResultSet
			int res = ps.executeUpdate();
			return res;
			
		}finally {	
			// 멀티 스레드로 실행되는 finally : 실행에 영향을 주지 않는다
			// 닫는 건 따로 실행된다 닫혀지니까 메모리에 남지 않고 그러면 오버플로우가 나지 않는다.
			if (ps != null) ps.close();
			if (con != null) pool.returnConnection(con);
		}
	}

모든 메서드를 수정해 줘야 하지만 간단하게 insertStudent 메서드만 보자면,

Connection con = pool.getConnection();

이 부분은 이제 새로 생성하는 것이 아닌 미리 생성해 뒀던 pool 객체로 connection 하면 된다.

if (con != null) pool.returnConnection(con);

여기도 이제 삭제하는 부분이 아니라 사용했으니 다시 돌려준다는 의미로 return 메서드만 실행해 주면 된다.

(3) .jsp 수정해 주기

<jsp:useBean id="stdao" class="my.student.StudentDAO"/>
<jsp:useBean id="pool" class="my.db.ConnectionPoolBean" scope="application"/>
<!-- scope: application 서버가 유지되는 동안 이 객체를 사용한다 -->
<jsp:setProperty name="stdao" property="pool" value="<%=pool%>"/>

그리고 dao 객체를 사용한 jsp 부분들을 수정해 주면 된다.
pool 을 사용해 객체의 값에 미리 생성된 pool 객체를 넣어 준다.
scope 값은 사용 범위를 말해 주는 건데 네 가지가 있다

- scope : 사용 범위

  • page : 현재 page 에서만 객체가 유효
  • request : 두 개의 page 에서 객체가 유효, 단 jsp 페이지 이동(forward, include)에서만 유효
  • session : 하나의 브라우저에서 객체가 유효
  • application : 같은 서버 내에서 객체가 유효

이곳에는 application 을 사용해 한 클라이언트에게 한 객체를 배정하는 시스템을 사용했다.

scope로 범위를 사용하여 JSP 페이지에서 데이터를 저장하고 공유할 수 있으며, 데이터의 수명 및 공유 범위를 명확하게 관리할 수 있다.

profile
자바 백엔드 개발자 개인 위키

0개의 댓글

관련 채용 정보