본문 바로가기
👨‍💻 2. 웹개발_Back end/2-4 JSP & Servlet

[JSP & Servlet] 5장 MVC 아키텍처 (7) - DB 커넥션풀

by 달님🌙 2021. 10. 17.
반응형

 

5.12 DB 커넥션풀

 

1. 싱글 커넥션

 

- 지금까지 우리가 만든 애플리케이션이 바로 싱글 커넥션 시스템이다.

 

- 싱글 커넥션을 사용하면 여러 개의 DAO가 같은 커넥션을 바라보게 됨

- 하나라도 롤백 작업이 일어나면 모든 작업이 취소가 됨

 

2. 싱글 커넥션 문제점과 해결책

 

1) 문제점

- 싱글 커넥션을 사용하면 같은 커넥션을 이용하는 DAO들의 작업에 영향을 준다.

 

2) 해결책1

- 하나의 DAO 객체마다 새로운 커넥션을 할당받아서 사용하는 시스템

- 이 방식의 문제점 : 일을 하지 않을 때도 커넥션을 물고 있어서 자원 낭비

 

3) 해결책2 (진짜 해결책)

- 한정된 자원을 효율적으로 사용하는 방법 :  대여 = 풀링(pooling) 기법

- DB 커넥션풀에다가 DB커넥션을 여러 개 만들어놓고 커넥션 요청이 올 때마다 빌려주고 끝나면 반환받는 시스템

 

3. DB 커넥션풀

 

1. 커넥션 풀( Connection pool ) 의미

커넥션 풀이란 DB와 미리 connection( 연결 )을 해놓은 객체들을 pool( 웅덩이 )에 저장해두었다가

클라이언트 요청이 오면 커넥션을 빌려주고, 볼일이 끝나면 다시 커넥션을 반납 받아 pool에 저장하는 방식 (풀링 방식)

 

- ProjectDao가 커넥션을 요청해서 DB커넥션풀이 100번 커넥션을 빌려줌

- ProjectDao는 100번 커넥션으로 작업을 진행하고 도중에 MemberDao도 커넥션 요청을 하게 됨

- 이미 만들어진 101번 커넥션을 MemberDao에게 빌려줌

 

- ProjectDao가 작업이 끝나서 100번 커넥션 풀을 반납하면 DB커넥션풀은 100번 커넥션을 보관한다.

 

 

- TaskDao가 커넥션 요청을 한 경우 DB커넥션풀에 보관되어 있던 100번 커넥션을 TaskDao에게 빌려주게 됨

- 커넥션을 다시 쓸 수 있도록 하는게 바로 풀링 시스템. 

 

4. DB 커넥션풀 실습

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);
		
		//미리 PRE_POOL_SIZE만큼 커넥션 생성
		for(int i = 0; i < PRE_POOL_SIZE; i++) {
			connList.add(DriverManager.getConnection(url, username, password));
		}
	}
	
	//Connection 객체 요청 시 Connection 대여
	public Connection getConnection() throws Exception {
		//현재 만들어진 커넥션 풀에 여유분이 존재하면
		if(connList.size() > 0) {
			Connection conn = connList.remove(0);
			//DB 커넥션이 유효하면 꺼낸 커넥션 리턴
			if(conn.isValid(10)) {
				return conn;
			}
		}
		
		//커넥션 풀에 여유분이 없을 경우 새로 커넥션을 만들어서 리턴
		return DriverManager.getConnection(url, username, password);
	}
	
	//빌려준 커넥션을 반환
	public void returnConnection(Connection conn) throws Exception {
		if(conn != null && conn.isClosed() == false) {
			connList.add(conn);
		}
	}
	
	//어플리케이션 종료 시 모든 Connection 종료
	public void closeAll() {
		System.out.println("connList.size()============" + connList.size());
		for(Connection conn : connList) {
			try {
				conn.close();
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
	}
}

 

ContextLoaderListener.java

package spms.listener;

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 {
	// Connection conn; 
	// 원래 만들어놓은 커넥션을 커넥션풀로 만들어주기
	DBConnectionPool connPool;
	
	@Override
	public void contextInitialized(ServletContextEvent sce) {
		//웹 어플리케이션이 실행되면 자동으로 DB커넥션 생성 및 MemeberDAO객체 생성
		try {
			System.out.println("contextInitialized");
			ServletContext sc = sce.getServletContext();
			Class.forName(sc.getInitParameter("driver"));
//			conn = DriverManager.getConnection(sc.getInitParameter("url"), 
//											   sc.getInitParameter("username"),
//											   sc.getInitParameter("password"));
			
			connPool = new DBConnectionPool(
											sc.getInitParameter("driver"),
											sc.getInitParameter("url"),
											sc.getInitParameter("username"),
											sc.getInitParameter("password"));
			
			MemberDAO memberDAO = new MemberDAO();
			memberDAO.setDBConnectionPool(connPool);
			
			//생성된 MemberDAO객체를 ServletContext 데이터 보관소를 통해 서블릿끼리 공유
			sc.setAttribute("memberDAO", memberDAO);
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public void contextDestroyed(ServletContextEvent sce) {
		try {
			System.out.println("contextDestroyed");
			connPool.closeAll();
		} 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 {
	/*
	 * Connection connection;
	 * 
	 * //DAO객체는 servlet이 아니기 때문에 servletcontext에 있는 커넥션 직접 접근 불가능
	 * //memberlistServlet에서 커넥션을 객체를 DAO에 주입해줄 것 public void
	 * setConnection(Connection connection) { this.connection = connection; }
	 */
	
	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;
		
		String sqlSelect = "SELECT * FROM MEMBERS ORDER BY MNO ASC";
		
		try {
			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"))
										.setCreateDate(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();
			}
			
			if(connection != null) {
				connPool.returnConnection(connection);
			}
		}
	}
	
	//MemberAddServlet에서 입력 폼으로 입력받은 데이터를 member객체로 담아서 
	//DAO로 전달할 예정
	public int insert(Member member) throws Exception {
		int result = 0;
		Connection connection = null;
		PreparedStatement stmt = null;
		final String sqlInsert = "INSERT INTO MEMBERS(EMAIL, PWD, MNAME, CRE_DATE, MOD_DATE)" +
												"VALUES(?, ?, ?, NOW(), NOW())";
		
		try {
			connection = connPool.getConnection();
			stmt = connection.prepareStatement(sqlInsert);
			stmt.setString(1, member.getEmail());
			stmt.setString(2, member.getPassword());
			stmt.setString(3, member.getName());
			//insert 성공하면 1 int 값 리턴
			result = stmt.executeUpdate();
		} catch(Exception e) {
			throw e;
		} finally {
			try {
				if(stmt != null) {
					stmt.close();
				}
			} catch(Exception e) {
				e.printStackTrace();
			}
			
			if(connection != null) {
				connPool.returnConnection(connection);
			}
		}
		
		return result;
	}
	
	public int delete(int no) throws Exception {
		int result = 0;
		Connection connection = null;
		Statement stmt = null;
		final String sqlDelete = "DELETE FROM MEMBERS WHERE MNO=" + no;
		
		try {
			connection = connPool.getConnection();
			stmt = connection.createStatement();
			result = stmt.executeUpdate(sqlDelete);
		} catch(Exception e) {
			throw e;
		} finally {
			try {
				if(stmt != null) {
					stmt.close();
				}
			} catch(Exception e) {
				e.printStackTrace();
			}
			
			if(connection != null) {
				connPool.returnConnection(connection);
			}
		}
		
		return result;
	}
	
	//해당 멤버 데이터 조회
	public Member selectOne(int no) throws Exception {
		Member member = null;
		Connection connection = null;
		Statement stmt = null;
		ResultSet rs = null;
		
		final String sqlSelectOne = "SELECT * FROM MEMBERS WHERE MNO=" + no;
		
		try {
			connection = connPool.getConnection();
			stmt = connection.createStatement();
			rs = stmt.executeQuery(sqlSelectOne);
			if(rs.next()) {
				member = new Member()
									 .setNo(rs.getInt("MNO"))
									 .setEmail(rs.getString("EMAIL"))
									 .setName(rs.getString("MNAME"))
									 .setCreateDate(rs.getDate("CRE_DATE"));
			} else {
				throw new Exception("해당 번호의 회원을 찾을 수 없습니다.");
			}
		} catch(Exception e) {
			throw e;
		} finally {
			try {
				if(stmt != null) {
					stmt.close();
				}
			} catch(Exception e) {
				e.printStackTrace();
			}
			
			if(connection != null) {
				connPool.returnConnection(connection);
			}
		}
		
		return member;
	}
	
	//해당 멤버 데이터 수정
	public int update(Member member) throws Exception {
		int result = 0;
		Connection connection = null;
		PreparedStatement stmt = null;
		
		final String sqlUpdate = "UPDATE MEMBERS SET EMAIL=?, MNAME=?, MOD_DATE=NOW() WHERE MNO=?";
		
		try {
			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) {
				e.printStackTrace();
			}
			
			if(connection != null) { 
				connPool.returnConnection(connection);
			}
		}
		
		return result;
	}
	
	public Member exist(String email, String password) throws Exception {
		Member member = null;
		Connection connection = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		
		final String sqlExist = "SELECT * FROM MEMBERS WHERE EMAIL=? AND PWD=?";
		
		try {
			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(stmt != null) {
					stmt.close();
				}
			} catch(Exception e) {
				e.printStackTrace();
			}
			
			if(connection != null) {
				connPool.returnConnection(connection);
			}
		}
		
		return member;
	}
}

 

- 하나의 서버로 10명이 접속해보기

- 커넥션을 요청하면 커넥션리스트에서 하나씩 꺼내서 커넥션을 리턴해줌

- 커넥션풀에 여유분이 없으면 새로 만들어서 리턴

 

 

5. 데이터 소스 이용하여 톰캣에서 DB커넥션 관리 실습

 

- 데이터베이스 인터페이스를 상속받아 객체 풀링을 자동 처리함

- 장점 : 활용성이 좋음, 범용적

 

1) ContextLoaderListener.java

package spms.listener;

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

import org.apache.commons.dbcp.BasicDataSource;

import spms.dao.MemberDAO;
import spms.util.DBConnectionPool;

public class ContextLoaderListener implements ServletContextListener {
	BasicDataSource ds;
	
	@Override
	public void contextInitialized(ServletContextEvent sce) {
		//웹 어플리케이션이 실행되면 자동으로 DB커넥션 생성 및 MemeberDAO객체 생성
		try {
			System.out.println("contextInitialized");
			ServletContext sc = sce.getServletContext();
			Class.forName(sc.getInitParameter("driver"));
		
			ds = new BasicDataSource();
			ds.setDriverClassName(sc.getInitParameter("driver"));
			ds.setUrl(sc.getInitParameter("url"));
			ds.setUsername(sc.getInitParameter("username"));
			ds.setPassword(sc.getInitParameter("password"));
			
			MemberDAO memberDAO = new MemberDAO();
			memberDAO.setDataSource(ds);
			
			//생성된 MemberDAO객체를 ServletContext 데이터 보관소를 통해 서블릿끼리 공유
			sc.setAttribute("memberDAO", memberDAO);
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public void contextDestroyed(ServletContextEvent sce) {
		try {
			System.out.println("contextDestroyed");
			if(ds != null) {
				ds.close();
			}
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
}

 

2) 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 javax.sql.DataSource;

import spms.vo.Member;

public class MemberDAO {
	/*
	 * Connection connection;
	 * 
	 * //DAO객체는 servlet이 아니기 때문에 servletcontext에 있는 커넥션 직접 접근 불가능
	 * //memberlistServlet에서 커넥션을 객체를 DAO에 주입해줄 것 public void
	 * setConnection(Connection connection) { this.connection = connection; }
	 */
	
	DataSource ds;
	
	public void setDataSource(DataSource ds) {
		this.ds = ds;
	}
	
	public List<Member> selectlist() throws Exception {
		Connection connection = null;
		Statement stmt = null;
		ResultSet rs = null;
		
		String sqlSelect = "SELECT * FROM MEMBERS ORDER BY MNO ASC";
		
		try {
			connection = ds.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"))
										.setCreateDate(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();
			}
			
			try {
				if(connection != null) {
					connection.close();
				}
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	//MemberAddServlet에서 입력 폼으로 입력받은 데이터를 member객체로 담아서 
	//DAO로 전달할 예정
	public int insert(Member member) throws Exception {
		int result = 0;
		Connection connection = null;
		PreparedStatement stmt = null;
		final String sqlInsert = "INSERT INTO MEMBERS(EMAIL, PWD, MNAME, CRE_DATE, MOD_DATE)" +
												"VALUES(?, ?, ?, NOW(), NOW())";
		
		try {
			connection = ds.getConnection();
			stmt = connection.prepareStatement(sqlInsert);
			stmt.setString(1, member.getEmail());
			stmt.setString(2, member.getPassword());
			stmt.setString(3, member.getName());
			//insert 성공하면 1 int 값 리턴
			result = stmt.executeUpdate();
		} catch(Exception e) {
			throw e;
		} finally {
			try {
				if(stmt != null) {
					stmt.close();
				}
			} catch(Exception e) {
				e.printStackTrace();
			}
			
			try {
				if(connection != null) {
					connection.close();
				}
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
		
		return result;
	}
	
	public int delete(int no) throws Exception {
		int result = 0;
		Connection connection = null;
		Statement stmt = null;
		final String sqlDelete = "DELETE FROM MEMBERS WHERE MNO=" + no;
		
		try {
			connection = ds.getConnection();
			stmt = connection.createStatement();
			result = stmt.executeUpdate(sqlDelete);
		} catch(Exception e) {
			throw e;
		} finally {
			try {
				if(stmt != null) {
					stmt.close();
				}
			} catch(Exception e) {
				e.printStackTrace();
			}
			
			try {
				if(connection != null) {
					connection.close();
				}
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
		
		return result;
	}
	
	//해당 멤버 데이터 조회
	public Member selectOne(int no) throws Exception {
		Member member = null;
		Connection connection = null;
		Statement stmt = null;
		ResultSet rs = null;
		
		final String sqlSelectOne = "SELECT * FROM MEMBERS WHERE MNO=" + no;
		
		try {
			connection = ds.getConnection();
			stmt = connection.createStatement();
			rs = stmt.executeQuery(sqlSelectOne);
			if(rs.next()) {
				member = new Member()
									 .setNo(rs.getInt("MNO"))
									 .setEmail(rs.getString("EMAIL"))
									 .setName(rs.getString("MNAME"))
									 .setCreateDate(rs.getDate("CRE_DATE"));
			} else {
				throw new Exception("해당 번호의 회원을 찾을 수 없습니다.");
			}
		} catch(Exception e) {
			throw e;
		} finally {
			try {
				if(stmt != null) {
					stmt.close();
				}
			} catch(Exception e) {
				e.printStackTrace();
			}
			
			try {
				if(connection != null) {
					connection.close();
				}
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
		
		return member;
	}
	
	//해당 멤버 데이터 수정
	public int update(Member member) throws Exception {
		int result = 0;
		Connection connection = null;
		PreparedStatement stmt = null;
		
		final String sqlUpdate = "UPDATE MEMBERS SET EMAIL=?, MNAME=?, MOD_DATE=NOW() WHERE MNO=?";
		
		try {
			connection = ds.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) {
				e.printStackTrace();
			}
			
			try {
				if(connection != null) {
					connection.close();
				}
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
		
		return result;
	}
	
	public Member exist(String email, String password) throws Exception {
		Member member = null;
		Connection connection = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		
		final String sqlExist = "SELECT * FROM MEMBERS WHERE EMAIL=? AND PWD=?";
		
		try {
			connection = ds.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(stmt != null) {
					stmt.close();
				}
			} catch(Exception e) {
				e.printStackTrace();
			}
			
			try {
				if(connection != null) {
					connection.close();
				}
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
		
		return member;
	}
}

 

3) Servers > Tomcat > context.xml

<!-- 톰캣 데이터 소스 설정 -->
<Resource name="jdbc/studydb" auth="Container" type="javax.sql.DataSource"
    MaxActive="10"
    MaxIdle="3"
    maxWait="10000"
    username="study"
    password="study"
    driverClassName="com.mysql.cj.jdbc.Driver"
    url="jdbc://mysql://localhost/studydb"
    closeMethod="close">
</Resource>

- name : JNDI 이름. Context의 lookup() 메소드 사용하여 자원을 찾을 때 사용

- auth : 데이터 소스 관리 주체 (Container|Application)를 설정 (우리는 Container에서 관리)

- type : 자원의 타입 설정

- MaxActive : 최대 커넥션 개수 설정 (몇개까지 커넥션을 유지할지)

- maxIdle : 최대 유지 가능한 사용하지 않는 커넥션 개수. 

               설정한 개수보다 많은 커넥션이 반환되면 반환되는 커넥션은 종료

               (3개 이상의 커넥션이 사용되지않을때 4번째 커넥션을 반환)


- maxWait : 연결 가능한 커넥션이 최대값에 도달했을 때 기다리는 시간(밀리초). 예) 10000 -> 10초

                 기다리는 시간동안 반환되는 커넥션이 없으면 예외를 던짐

- close : 톰캣 서버 종료 시 자원 해제를 위해 호출할 메소드 설정 

 

* 사용자가 많지 않은 경우 3~4개의 커넥션으로도 충분

 

4) web.xml에 데이터소스 참조하는 코드인 resource-ref 추가

  <!-- 데이터소스 참조 -->
  <resource-ref>
  	<res-ref-name>jdbc/studydb</res-ref-name>
  	<res-type>javax.sql.DataSource</res-type>
  	<res-auth>Container</res-auth>
  </resource-ref>

 

5) JNDI (Java Naming and Directory Interface) 의미

- 디렉터리 서비스에서 제공하는 데이터 및 객체를 발견(discover)하고 참고(lookup)하기 위한 자바 API다.

- WAS의 자원에 대한 고유 이름 정의

- 어플리케이션에서 서버 리소스를 접근할 때 사용하는 명명 규칙

* 1) java:comp/env         	 - 응용 프로그램 환경 항목
* 2) java:comp/env/jdbc    	 - JDBC 데이터 소스
* 3) java:comp/ejb         	 - EJB 컴포넌트
* 4) java:comp/UserTransaction  - UserTransaction 객첵
* 5) java:comp/env/mail    	 - JavaMail 연결 객체
* 6) java:comp/env/url     	 - URL 정보
* 7) java:comp/env/jms     	 - JMS 연결 객체

 

6) ContextLoaderListener.java

package spms.listener;

import javax.naming.InitialContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSource;

import spms.dao.MemberDAO;

public class ContextLoaderListener implements ServletContextListener {
	//datasource의 장점  커넥션풀을 톰캣에서 지원해주기 때문에 
	//개발자가 직접  connection pool 객체를 만들어 줄 필요가 없다
	//BasicDataSource ds;
	
	@Override
	public void contextInitialized(ServletContextEvent sce) {
		//웹 어플리케이션이 실행되면 자동으로 DB커넥션 생성 및 MemeberDAO객체 생성
		try {
			System.out.println("contextInitialized");
			ServletContext sc = sce.getServletContext();
			
			//톰캣 서버에서 자원(커넥션)을 찾기 위한 InitailContext 객체 생성
			InitialContext initialcontext = new InitialContext();
			/*
			 * JNDI 사용
			 * WAS의 자원에 대한 고유 이름 정의
			 * 어플리케이션에서 서버 리소스를 접근할 때 사용하는 명명 규칙(톰캣)
			 * 서버마다 명명 규칙은 다름 (제우스는 또다른 규칙이 있음)
			 * 
			 * 1) java:comp/env         	 - 응용 프로그램 환경 항목
			 * 2) java:comp/env/jdbc    	 - JDBC 데이터 소스
			 * 3) java:comp/ejb         	 - EJB 컴포넌트
			 * 4) java:comp/UserTransaction  - UserTransaction 객첵
			 * 5) java:comp/env/mail    	 - JavaMail 연결 객체
			 * 6) java:comp/env/url     	 - URL 정보
			 * 7) java:comp/env/jms     	 - JMS 연결 객체
			 * 
			 * */
			DataSource ds = (DataSource)initialcontext.lookup("java:comp/env/jdbc/studydb");
			
			/*
			 * ds = new BasicDataSource();
			 * ds.setDriverClassName(sc.getInitParameter("driver"));
			 * ds.setUrl(sc.getInitParameter("url"));
			 * ds.setUsername(sc.getInitParameter("username"));
			 * ds.setPassword(sc.getInitParameter("password"));
			 */
			
			MemberDAO memberDAO = new MemberDAO();
			memberDAO.setDataSource(ds);
			
			//생성된 MemberDAO객체를 ServletContext 데이터 보관소를 통해 서블릿끼리 공유
			sc.setAttribute("memberDAO", memberDAO);
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public void contextDestroyed(ServletContextEvent sce) {
		try {
			System.out.println("contextDestroyed");
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
}

 

7) 실행 화면

 

 

반응형

댓글