1. 트랜잭션 처리
트랜잭션은 데이터처리를 모두 일관되게 하기 위해서 반드시 수행되어야하는 작업이다.
트랜잭션을 구현하는 방법으로는
JDBC의 오토 커밋 모드를 false로 지정 → 단일 데이터베이스에 접근하는 경우
JTA(Java Tansaction API)를 이용 → 두개 이상의 데이터베이스를 처리하는 경우
코드를 살펴 보자
try{
conn = DriverManager.getConnection(jdbcDriver,dbUser,dbPass);
//트랜잭션 시작
conn.setAutoCommit(false);
... //쿼리 실행1
... //쿼리 실행2
//트랜잭션 커밋
conn.commit();
}catch(SQLException e){
//오류 발생시 트랜잭션 롤백
if( conn!=null)
conn.rollback()
}
}finally{
if(conn!=null)try{conn.close();}catch(SQLException e){}
}
2. 커넥션 풀
이전 방식은 작업이 필요할 때 작업이 필요할 때마다 커넥션을 생성해서 사용했다. 이 방식은 지속적으로 시간이 소모되기 때문에 동시 접속자가 많은 웹사이트에서는 전체 성능이 낮아진다. 이를 해결하기 위해서 나온 방식이 커넥션 풀이다.
커넥션 풀을 사용하기 위해서는 DBCP 관련 파일들이 있어야한다.
이 파일들은 https://search.maven.org/ 에서 다운 받을 수 있다.
이후 서블릿 클래스를 작성해야 한다.
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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | package jdbc; import java.sql.DriverManager; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import org.apache.commons.dbcp2.ConnectionFactory; import org.apache.commons.dbcp2.DriverManagerConnectionFactory; import org.apache.commons.dbcp2.PoolableConnection; import org.apache.commons.dbcp2.PoolableConnectionFactory; import org.apache.commons.dbcp2.PoolingDriver; import org.apache.commons.pool2.impl.GenericObjectPool; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; @SuppressWarnings("serial") public class DBCPInit extends HttpServlet{ @Override public void init() throws ServletException { loadJDBCDriver(); initConnectionPool(); } private void loadJDBCDriver() { try { Class.forName("com.mysql.jdbc.Driver"); }catch(ClassNotFoundException ex) { throw new RuntimeException("fail to load JDBC Driver",ex); } } private void initConnectionPool() { try { String jdbcUrl = "jdbc:mysql://localhost:3306/DBname?" + "useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC"; String userName="userid"; String userPassword = "userpwd"; ConnectionFactory connFactory = new DriverManagerConnectionFactory(jdbcUrl,userName,userPassword); PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connFactory, null); poolableConnectionFactory.setValidationQuery("select 1"); GenericObjectPoolConfig poolConfig= new GenericObjectPoolConfig(); poolConfig.setTimeBetweenEvictionRunsMillis(1000L*60L*5L); poolConfig.setTestWhileIdle(true); poolConfig.setMinIdle(4); poolConfig.setMaxTotal(50); GenericObjectPool<PoolableConnection> connectionPool = new GenericObjectPool<PoolableConnection>(poolableConnectionFactory,poolConfig); poolableConnectionFactory.setPool(connectionPool); Class.forName("org.apache.commons.dbcp2.PoolingDriver"); PoolingDriver driver=(PoolingDriver)DriverManager.getDriver("jdbc:apache:commons:dbcp:"); driver.registerPool("chap14", connectionPool); }catch (Exception e) { System.out.println("exception e"); throw new RuntimeException(e); } } } | cs |
각 과정은
실제 커넥셜을 생성할 ConnectionFactionFactory를 생성한다.
커넥셜 풀로 사용할 PoolableConnection을 생성하는 PoolableConnectionFactory를 생성한다.
커넥션 풀의 설정 정보를 생성한다.
커넥션 풀을 사용할 JDBC드라이버를 등록한다.
이 과정을 거친다.
소스코드를 작성했으므로 서블릿을 지정해주어야한다. web.xml 에 이 부분을 추가해준다.
<servlet>
<servlet-name>DBCPInit</servlet-name>
<servlet-class>jdbc.DBCPInit</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
이전 방식은 JDBC 드라이버를 로드한 이후에 여기서 커넥션을 바로 가져왔다 하지만 지금은 풀을 사용하므로 먼저 풀드라이버를 로드해서 접근할 수 있게 만들고 이후에
JDBC 드라이버를 이용해 이 풀에 접근해야 한다.
즉
Class.forName("org.apache.commons.dbcp2.PoolingDriver");
PoolingDriver driver=(PoolingDriver)DriverManager.getDriver("jdbc:apache:commons:dbcp:");
driver.registerPool("poolName", connectionPool);
그리고 여기서 풀의 이름을 poolName으로 했으므로 이 풀을 사용하는 JSP페이지에서는 이렇게 작성 하면된다.
Connection conn =null;
try{
String jdbcDriver = "jdbc:apache:commons:dbcp:poolName";
// 커넥션 풀에서 커넥션을 구하는 것이다.
DriverManager.getConnection(jdbcDriver);
...
}finally{
//커넥션을 풀에 반환
if(conn!=null)try { conn.close();}catch(SQLException
다음으로 커넥션 풀 속성에 대해서 설명 하겠다.
GenericObjectPoolConfig poolConfig=
new GenericObjectPoolConfig();
poolConfig.setTimeBetweenEvictionRunsMillis(1000L*60L*5L);
poolConfig.setTestWhileIdle(true);
poolConfig.setMinIdle(4);
poolConfig.setMaxTotal(50);
이러한 코드가 있는데 바로 여기서 커넥션에 대한 속성을 설정 한다.
GenericObjecPoolConfig 클래스를 사용하여 설정할 수 있다.
일단 API 주소를 남기니 참고하시길 (http://www.shbaseball.co.kr/index.hs)
이를 이용하면 커넥션 풀의 최대 크기, 커넥션의 검사 주기 등을 설정할 수 있는 매서드를 제공하고 있다.
이 외에도 유휴 커넥션을 제거하는 기능을 제공한다.
커넥션 풀에 있는 커넥션 중 오랜 시간 동안 사용되지 않는 커넥션은 DBMS와 연결이 끊길 가능성이 높다. 따라서 유휴 커넥션을 검사하여 제거해줘야한다.
1. 커넥션이 최소 유휴 시간보다 오래 풀에 있는 경우 (MinEvictableIdleTimeMillis 검사)
2. 커넥션이 유효한지 여부 확인 (TestWhileIdle)
이 두 속성은 검사 주기 (TimeBetweenEvictionRunsMillis) 값이 양수일때 적용 된다
이후에 유휴 커넥션이 유효한지 검사한다면 검사할 때 사용할 쿼리를 지정해주면 된다.
PoolableConnectionFactory poolableConnectionFactory =
new PoolableConnectionFactory(connFactory, null);
poolableConnectionFactory.setValidationQuery("select 1");
※ setValidationQuery 가 검사할 때 사용할 쿼리를 지정하는 매서드이다. 여기서 'select 1' 크게 의미 없는 쿼리인데 다만 커넥션이 끊킨 유효하지 않은 커넥션을 잡아주기 위한 것이다. 쿼리를 보냈을 때 오류가는 커넥션이 유효하지 않은 커넥션이기 때문에 가장 DB 부하가 적은 쿼리를 보내느 것이다.
풀속성에 대해 정리를 하면
maxTotal : 이 값이 불필요하게 커질 경우 커넥션 개수가 비대하게 늘어나 DBMS가 수용할 수 있는 수준을 넘어서면 오히려 전체 성능에 좋지 않은 영향을 끼칠 수 있다.
minIdle : 사용되지 않는 커넥션의 최소 개수를 0으로 지정하면 풀에 저장된 커넥션 개수가 0이 될 수 있다.
timeBetweenEvictionRunsMillis : 이 값을 설정해서 주기적으로 유휴 커넥션을 풀어서 제거하는 것이 좋다.
testWhileIdle : 유휴 커넥션을 검사할 때 유효하지 않은 커넥션도 검사해서 연결이 끊긴 커넥션을 사전에 제거하는 것이 좋다.
maxWaitMillis : 커넥션 풀에 커넥션이 없으면 일정 시간 대기 후 익셉션을 발생시키는 것이 좋다. 그렇지 않으면 클라이언트는 무한정 대기하게 될 수도 있다
JSP 공부 <7> - 모델1 구조 간단 그림 정리 (0) | 2018.09.26 |
---|---|
JSP 공부 <5> - 데이터 베이스 생성 과 SQL (0) | 2018.09.15 |
JSP 공부 <4> - 데이터 베이스 기초 (0) | 2018.09.15 |
JSP 공부 <3> - 모델1 , 모델2 , MVC패턴 ? (0) | 2018.09.10 |
JSP 공부 <2> - JSTL , EL 연습 (0) | 2018.09.07 |