커넥션풀
여러명의 사용자가 하나의 DB커넥션을 공유하는경우
하나의 데이터베이스의 연결로 요청을 처리하다가 예외가 발생해 롤백한 경우에는
다른 요청에 대해 작업한 내용까지 모두 롤백되는 문제가 있다.
웹 사이트에 접속하는 사용자의수가 많으면
웹 서버 상에서 동시 실행되는웹 애플리케이션의 수도 아주 많을것이다.
그런 프로그램들이 동시에 같은 데이터베이스에 연결을 시도하는경우도 많다.
많은 상용DBMS들이 데이터베이스에 동시에 연결할 수 있는 수를 제한하고 있다.
데이터베이스에 대한 연결은 컴퓨터 자원을 상당히 많이 소모하기 때문에
동시 사용자의 수가 아주 많은 웹 사이트에서는 웹 애플리케이션 프로그램마다
제각각 데이터베이스로의 연결을 맺는것이 사실상 불가능하다.
커넥션 풀은 이런 문제를 해결하기 위한 장치이다.
여러개의 연결을 미리 맺어놓은 후에 그것을 한데 모아놓고
웹 애플리케이션이 필요할 때마다 가져가서 사용한 후 반환하는 방식을 풀링 이라 하고
커넥션 객체들을 한데 모아놓고 필요할때 가져가서 사용후 반환하는 장소를 객체 풀 이라 한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | public class DBConnectionPool { String url; String username; String password; ArrayList<Connection> connList = new ArrayList<Connection>(); //커넥션 객체들을 담을 ArrayList 객체 생성 //생성자 메서드 public DBConnectionPool(String driver, String url, String username, String password) throws Exception { //드라이버 클래스의 이름,db연결주소,ID,패스워드를 매개변수로 받고 드라이버를 로드 this.url = url; this.username = username; this.password = password; Class.forName(driver); } //커넥션 객체 요청시 ArrayList에서 꺼내오는 메서드 public Connection getConnection() throws Exception { if (connList.size() > 0) {//조건1 ArrayList에 커넥션 객체가 존재할경우 Connection conn = connList.remove(0); //객체풀의 0번인덱스 참조값을 제거하고 참조값이 제거된 해당 인스턴스 반환 if (conn.isValid(10)) {//조건1-1 해당 객체의 유효성을 검사한다. 매개변수인 10은 대기시간(초) return conn;//위의 조건이 일치하다면 커넥션 객체 반환 } } //보유한 객체가 없다면 새로운 객체를 생성해 return DriverManager.getConnection(url, username, password); } //객체사용후 돌려주는 메서드 public void returnConnection(Connection conn) throws Exception { connList.add(conn);//매개변수로 받은 커넥션 객체를 ArrayList에 추가 } //데이터베이스와 연결된 모든 커넥션객체들의 연결을 끊는 메서드 public void closeAll() { for(Connection conn : connList) { try{conn.close();} catch (Exception e) {} } } } | cs |
DataSource
DataSource는 javax.sql 패키지에 포함된 인터페이스다. 자체적으로 커넥션 풀의 기능을 구현한다.
DriverManager보다 좋은 방법으로 db의 커넥션을 얻을수 있다.
DataSource는 서버에사 관리하기 때문에 데이터베이스나 JDBC드라이버가 변경되어도 애플리케이션을 바꿀 필요가 없다.
Connection과Statement객체를 풀링할수 있고 분산 트랜잭션을 다룰수 있다.
사용방법
톰캣 폴더의 context.xml 파일을 열고 편집한다. or META-INF/context.xml
| <Context> <Resource name="jdbc/mysql" auth="Container" type="javax.sql.DataSource" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://192.168.123.145:3306/ace ?useUnicode=true&characterEncoding=euckr" username="ace" password="java0000" maxActive="100" maxIdel="30" maxWait="5000" factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" closeMethod="close"/> </Context> | cs |
태그 속성
name : JNDI 이름,
auth : 자원관리의 주체 지정 Application또는Container 가능
type : 자원의 타입 지정 패키지이름을 포함한 클래스 이름
draverClassName : JDBC드라이버 클래스의 이름(패키지 이름포함)
url : 데이터베이스 커넥션 url
username : 데이터베이스 사용자 이름
password : 데이터베이스 사용자 암호
maxActive : dataSource로부터 꺼낼수있는 커넥션의 최대 개수
maxIdle : dataSource에서 유지할수 있는 사용되지 않는 커넥션의 최대 개수 ,
최대유지 개수를 넘어서 반납되는 커넥션은 닫아버린다 기본값 8개
maxWait : 발급한 커넥션의 수가 최대값에 도달한 상태에서 커넥션을 달라는 요청이 들어왔을때
커넥션 준비를 위해 기다리는 최대 밀리초 최대 밀리초가 지날 때까지 반납되는 커넥션이 없으면 예외를 던진다.
기본값은 -1 커넥션 반납시까지 기다림
closeMethod : 톰캣 서버가 종료될 때 자원을 해제하기 위해 호출 close로 지정될경우 자동으로 해제
web.xml 안에 resource-ref 태그 작성
| <web-app> <resource-ref> <res-ref-name>jdbc/mysql</res-ref-name> <!-- JDNI이름 --> <res-type>javax.sql.DataSource</res-type> <!-- 리턴될 자원의 클래스 이름 context.xml에 선언된것과 같아야한다. --> <res-auth>Container</res-auth> <!-- 자원 관리의 주체 Container는 서버에서 관리한다는 의미--> </resource-ref> </web-app> | cs |
사용방법 예시
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public class ContextLoaderListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent event) { //웹애플리케이션이 시작될 때 실행되는 메서드 try { ServletContext sc = event.getServletContext(); //Context 객체 가져옴 InitialContext initialContext = new InitialContext(); //톰캣 서버의 자원을 찾기위한 객체 lookup 메서드로 자원을 찾을수 있다. DataSource ds = (DataSource)initialContext.lookup( "java:comp/env/jdbc/mysql"); //매개변수는 자원의 JDNI 이름 리턴데이터타입이 DataSource이기때문에 형변환 MemberDao memberDao = new MemberDao(); memberDao.setDataSource(ds); //dao객체에 DataSource sc.setAttribute("memberDao", memberDao); } catch(Throwable e) { e.printStackTrace(); } } | cs |