DBCP API를 이용하여 커넥션 풀을 사용하는 방법에 대해서 살펴본다.

커넥션 풀과 자카르타 DBCP API

DBCP API는 커넥션 풀 기능을 제공하는 API로서 자카르타의 또 다른 프로젝트인 Pool API에 기반하고 있다. DBCP API는 사용방법이 비교적 쉬우며, 파일을 통해서 커넥션 풀을 설정할 수 있고 또한 프로그램에서 직접 커넥션 풀을 설정할 수 있기 때문에 커넥션 풀을 사용하려는 개발자에게 매우 유용한 API이다.

커넥션 풀이란?

커넥션 풀에 대한 개념이 없는 사람을 위해 DBCP API를 이용한 커넥션 풀에 대해서 살펴보기 전에 간단하게 커넥션 풀이 무엇인지에 대해서 살펴보도록 하자. 커넥션 풀 기법이란 데이터베이스와 연결된 커넥션을 미리 만들어서 풀(pool)이란 저장소에 저장해 두고 있다가 필요할 때에 커넥션을 풀에서 가져다 쓰고 다시 풀에 반환하는 기법을 의미한다


커넥션 풀 기법에서는 위 그림과 같이 풀 속에 데이터베이스와 연결된 커넥션을 미리생성해놓고 있는다. 데이터베이스 커넥션이 필요할 경우, 커넥션을 새로 생성하는 것이 아니라 풀 속에 미리 생성되어 있는 커넥션을 가져다가 사용하게 된다. 다 사용한 커넥션은 다시 풀에 반환한다. 풀에 반환된 커넥션은 다음에 다시 사용된다.

커넥션 풀의 특징은 다음과 같다.

  • 풀 속에 미리 커넥션이 생성되어 있기 때문에 커넥션을 생성하는 데 드는 연결 시간이 소비되지 않는다.
  • 커넥션을 계속해서 재사용하기 때문에 생성되는 커넥션 수가 많지 않다.

커넥션을 생성하고 닫는 데 필요한 시간이 소모되지 않기 때문에 그 만큼 어플리케이션의 실행 속도가 빨라지며, 또한 한번에 생성될 수 있는 커넥션 수를 제어하기 때문에 동시 접속자수가 몰려도 웹 어플리케이션이 쉽게 다운되지 않는다.

커넥션 풀을 사용하면 전체적인 웹 어플리케이션의 성능 및 처리량이 높아지기 때문에 많은 웹 어플리케이션에서 커넥션 풀을 기본으로 사용하고 있다.

DBCP API의 사용방법

자카르타 프로젝트의 DBCP API를 사용할 때에는 다음과 같은 과정을 거치면 된다.

  1. DBCP 관련 Jar 파일 및 JDBC 드라이버 Jar 파일 설치하기
  2. 커넥션 풀 관련 설정 파일 초기화하기
  3. 커넥션 풀 관련 드라이버 로딩하기
  4. 커넥션 풀로부터 커넥션 사용하기

이 네 가지 절차에 대해서 차례대로 살펴보도록 하자.

필요한 Jar 파일 복사

DBCP API를 사용하기 위해서는 다음과 같은 라이브러리가 필요하다.

  • DBCP API 관련 Jar 파일
  • DBCP API가 사용하는 자카르타 Pool API의 Jar 파일
  • Pool API가 사용하는 자카르타 Collection API의 Jar 파일

이들 라이브러리의 최신 버전은 http://jakarta.apache.org/site/binindex.cgi 에서 다운로드 받을 수 있으며, 이 글에서는 다음 버전을 사용하여 예제를 작성하였다.

  • DBCP 1.2.1 - commons-dbcp-1.2.1.zip
  • Pool 1.2 - commons-pool-1.2.zip
  • Collection 3.1 - commons-collections-3.1.zip

이들 파일의 압축을 풀면 다음과 같은 Jar 파일들을 발견할 수 있는데, 이들 Jar 파일들을 사용하면 된다.

  • commons-dbcp-1.2.1.jar
  • commons-pool-1.2.jar, commons-collections-3.1.jar

예제로 제공되는 파일에는 pool\WEB-INF\lib 폴더에는 이미 이들 Jar 파일들이 포함되어 있으므로 별도로 복사하지 않더라도 DBCP를 사용하는 본 장의 예제들을 실행할 수 있게 된다.

커넥션 풀 설정 파일 작성하기

DBCP를 사용하는 방법에는 소스 코드 상에서 커넥션 풀을 설정하는 방법과 설정 파일을 통해서 커넥션 풀을 설정하는 방법 두가지 존재하는데 본 장에서는 설정 파일을 이용한 커넥션 풀 설정 방법에 대해서 살펴보도록 하겠다.

DBCP Pool API에서 사용되는 커넥션 풀 설정 파일의 기본 골격은 아래 코드와 같다.

    
    파일명: pool\WEB-INF\classes\pool1.jocl    
    <object class="org.apache.commons.dbcp.PoolableConnectionFactory"
        xmlns="http://apache.org/xml/xmlns/jakarta/commons/jocl">
      <object class="org.apache.commons.dbcp.DriverManagerConnectionFactory">
        <string value="jdbc:mysql://localhost:3306/.." />
        <string value="jspexam" />
        <string value="jspex" />
      </object>      
      <object class="org.apache.commons.pool.impl.GenericObjectPool">
        <object class="org.apache.commons.pool.PoolableObjectFactory" null="true" />
      </object>
      
      <object class="org.apache.commons.pool.impl.GenericKeyedObjectPoolFactory"
              null="true" />
            <string null="true" />
            <boolean value="false" />
            <boolean value="true" />
    </object>


위 코드에서 나머지 부분은 그대로 입력하고 다음 부분만 알맞게 변경하면 된다.

    <object class="org.apache.commons.dbcp.DriverManagerConnectionFactory">
      <string value="jdbc:mysql://localhost:3306/..." />
      <string value="jspexam" />
      <string value="jspex" />
    </object>


위 코드에는 세 개의 <string> 태그가 사용되는데, 이들 태그는 각각 순서대로 JDBC URL, 데이터베이스 사용자 계정, 암호를 나타낸다.

설정 파일의 위치

DBCP API는 클래스패스로부터 설정 파일을 읽어온다. 따라서 앞서 작성한 커넥션 풀 설정 파일은 클래스패스에 위치해 있어야 한다. 웹 어플리케이션에서 DBCP API와 관련된 설정 파일의 위치로 가장 좋은 곳은 WEB-INF\classes 폴더이다. 본 글의 예제에서 사용하는 커넥션 풀 설정 파일은 모두 WEB-INF\classes 폴더에 위치시켰다.

커넥션 풀 초기화

DBCP API를 통해서 커넥션 풀을 사용하기 위해서는 커넥션 풀과 관련된 JDBC 드라이버를 로딩해주어야 한다. DBCP API를 사용할 때에 로딩해주어야 할 JDBC 드라이버는 다음과 같다.

  • org.apache.commons.dbcp.PoolingDriver - DBCP API의 JDBC 드라이버
  • DBMS에 연결할 때 사용될 JDBC 드라이버

웹 어플리케이션 시작할 때 위에서 언급한 두 가지 형태의 JDBC 드라이버를 로딩하도록 하면 편리할 것이다. 웹 어플리케이션이 시작할 때 자동으로 시작되는 JDBC 드라이버를 로딩하도록 구현한 서블릿 클래스는 다음 코드와 같다.

    
    파일명: pool\WEB-INF\src\madvirus.jdbcdriver\DBCPInit.java    
    package madvirus.jdbcdriver;
    
    import javax.servlet.http.HttpServlet;
    import javax.servlet.ServletConfig;
    import javax.servlet.ServletException;
    import java.util.StringTokenizer;
    
    public class DBCPInit extends HttpServlet {
    
        public void init(ServletConfig config) throws ServletException {
            try {
                String drivers = config.getInitParameter("jdbcdriver");
                StringTokenizer st = new StringTokenizer(drivers, ",");
                while (st.hasMoreTokens()) {
                    String jdbcDriver = st.nextToken();
                    Class.forName(jdbcDriver);
                }
                
                Class.forName("org.apache.commons.dbcp.PoolingDriver");                
                System.setProperty("org.xml.sax.drvier",
                       "org.apache.crimson.parser.XMLReaderImpl");
            } catch(Exception ex) {
                throw new ServletException(ex);
            }
        }
    }


DBCPInit 서블릿은 "jdbcdriver" 초기화 파라미터로부터 로딩할 JDBC 드라이버를 입력받아 JDBC 드라이버를 차례대로 로딩한다. 그런 후, DBCP API의 JDBC 드라이버인 PoolingDriver 을 로딩한다. 마지막으로 설정 파일을 분석할 때 사용할 XML 파서를 지정한다. 위 코드는 Sun 사에서 배포한 JDK 1.4를 기준으로 XML 파서를 지정하였는데, 만약 다른 XML 파서를 사용한다면 알맞게 변경해주어야 한다.

WEB-INF\web.xml 파일에 DBCPInit 서블릿 클래스에 대한 설정 정보를 추가함으로써 웹 어플리케이션이 시작될 때 DBCPInit 서블릿 클래스가 시작될 수 있도록 할 수 있다. 예를 들면, 아래와 같은 코드를 web.xml 파일에 추가해주면 된다.

  <servlet>
     <servlet-name>DBCPInit</servlet-name>
     <servlet-class>madvirus.jdbcdriver.DBCPInit</servlet-class>
     <load-on-startup>1</load-on-startup>
     <init-param>
        <param-name>jdbcdriver</param-name>
        <param-value>com.mysql.jdbc.Driver</param-value>
     </init-param>
  </servlet>


위와 같이 코드를 web.xml 파일에 추가해주면 웹 어플리케이션이 시작할 때 DBCPInit 서블릿 클래스가 자동으로 시작되고 init() 메소드가 호출된다.

커넥션 풀로부터 커넥션 사용하기

커넥션 풀을 위한 JDBC 드라이버 및 DBMS에 연결할 때 사용할 JDBC 드라이버를 로딩하면 커넥션 풀로부터 커넥션을 가져와 사용할 수 있다. 커넥션 풀로부터 커넥션을 가져오는 코드는 별반 다르지 않으며, 다음과 같은 형태의 코드를 사용하면 된다.

    Connection conn = null;
    ....
    try {
        String jdbcDriver = "jdbc:apache:commons:dbcp:/pool1";
        conn = DriverManager.getConnection(jdbcDriver);
        ...
    } finally {
        ...
        if (conn != null) try { conn.close(); } catch(SQLException ex) {}
    }


위 코드를 보면 DBCP API 기반의 커넥션 풀을 사용한다고 해서 특별히 코드가 달라지는 부분이 없다는 것을 알 수 있다. 일반 경우와 마찬가지로 DriverManager.getConnection() 메소드를 사용해서 커넥션을 구해오고, 커넥션을 다 사용하면 close() 메소드를 사용하여 사용한 커넥션을 닫는다. 차이점이라면 JDBC URL이 다음과 같은 형태를 띈다는 점이다.

    jdbc:apache:commons:dbcp:/[풀이름]


[풀이름]은 여러 개의 커넥션 풀 중에서 사용할 커넥션 풀의 이름을 나타내는 것으로서 커넥션 풀 설정 파일에서 확장자를 제외한 나머지 이름을 [풀이름]으로 사용한다. 예를 들어, 앞서 작성했었던 pool1.jocl 파일이 설정한 커넥션 풀을 사용하고 싶다면 다음과 같은 JDBC URL을 사용한다.

    jdbc:apache:commons:dbcp:/pool1


실제로 커넥션 풀을 사용하는 완전한 예제는 다음 코드와 같다. (아래 코드를 여러분의 환경에 알맞게 변형시켜서 실행하기 바란다.)

    
    파일명: pool\usePool1.jsp    
    <%@ page contentType = "text/html; charset=euc-kr" %>
    
    <%@ page import = "java.sql.DriverManager" %>
    <%@ page import = "java.sql.Connection" %>
    <%@ page import = "java.sql.Statement" %>
    <%@ page import = "java.sql.ResultSet" %>
    <%@ page import = "java.sql.SQLException" %>
    
    <html>
    <head><title>회원 목록</title></head>
    <body>
    
    MEMBMER 테이블의 내용
    <table width="100%" border="1">
    <tr>
        <td>이름</td><td>아이디</td><td>이메일</td>
    </tr>
    <%
        
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        
        try {
            String jdbcDriver = "jdbc:apache:commons:dbcp:/pool1";
            String query = "select * from MEMBER order by MEMBERID";
            conn = DriverManager.getConnection(jdbcDriver);
            stmt = conn.createStatement();
            rs = stmt.executeQuery(query);
            while(rs.next()) {
    %>
    <tr>
        <td><%= rs.getString("NAME") %></td>
        <td><%= rs.getString("MEMBERID") %></td>
        <td><%= rs.getString("EMAIL") %></td>
    </tr>
    <%
            }
        } finally {
            if (rs != null) try { rs.close(); } catch(SQLException ex) {}
            if (stmt != null) try { stmt.close(); } catch(SQLException ex) {}
            if (conn != null) try { conn.close(); } catch(SQLException ex) {}
        }
    %>
    </table>
    
    </body>
    </html>


위 코드에서 커넥션 풀에서 구한 Connection의 close() 메소드를 호출하면, 커넥션이 닫히는 것이 아니라 커넥션 풀로 반환된다. 이렇게 커넥션 풀에 커넥션을 반환하는 메소드를 close()로 지정한 이유는 기존의 코드를 최소한으로 변경하는 범위 내에서 커넥션 풀을 사용할 수 있도록 하기 위함이다. 물론, JDBC 프로그래밍의 코딩 형태를 동일하게 유지하기 위한 것도 close() 메소드를 사용하는 이유이다.

커넥션 풀 속성 지정하기

앞에서 살펴본 커넥션 풀 설정 파일인 pool1.jocl은 커넥션 풀과 관련된 속성을 지정하지 않고 있다. DBCP의 커넥션 풀은 최대 커넥션 개수, 최소 유휴 커넥션 개수, 최대 유휴 커넥션 개수, 유휴 커넥션 검사 여부 등의 속성을 지정할 수 있다. pool1.jocl을 보면 다음과 같은 코드가 있는데,

  <object class="org.apache.commons.pool.impl.GenericObjectPool">
    <object class="org.apache.commons.pool.PoolableObjectFactory" null="true" />
  </object>


이 코드에 커넥션 풀과 관련된 속성 정보를 추가하면 된다. 예를 들면, 아래 코드와 같이 커넥션 풀 속성 정보를 추가하면 된다.

    
    파일명: pool\WEB-INF\classes\pool2.jocl    
    <object class="org.apache.commons.dbcp.PoolableConnectionFactory"
        xmlns="http://apache.org/xml/xmlns/jakarta/commons/jocl">
    
      <object class="org.apache.commons.dbcp.DriverManagerConnectionFactory">
        <string value="jdbc:mysql://localhost:3306/chap11?..." />
        <string value="jspexam" />
        <string value="jspex" />
      </object>
      
      <object class="org.apache.commons.pool.impl.GenericObjectPool">
        <object class="org.apache.commons.pool.PoolableObjectFactory" null="true" />
        <int value="10" />  <!-- maxActive -->
        <byte value="1" />  <!-- whenExhaustedAction -->
        <long value="10000" /> <!-- maxWait -->
        <int value="10" /> <!-- maxIdle -->
        <int value="3" /> <!-- minIdle -->
        <boolean value="true" /> <!-- testOnBorrow -->
        <boolean value="true" /> <!-- testOnReturn -->
        <long value="600000" /> <!-- timeBetweenEvctionRunsMillis -->
        <int value="5" /> <!-- numTestsPerEvictionRun -->
        <long value="3600000" /> <!-- minEvictableIdleTimeMillis -->
        <boolean value="true" /> <!-- testWhileIdle -->
      </object>      
      <object class="org.apache.commons.pool.impl.GenericKeyedObjectPoolFactory"
          null="true" />
      
      <string null="true" />
      
      <boolean value="false" />
      
      <boolean value="true" />
    </object>


굵게 표시한 부분이 커넥션 풀의 속성과 관련된 부분인데, 각 속성의 값이 무엇을 의미하는 지 우측에 주석으로 표시하였다. 각 속성이 의미하는 것은 다음표와 같다.

속성설명
maxActive커넥션 풀이 제공할 최대 커넥션 개수
whenExhaustedAction커넥션 풀에서 가져올 수 있는 커넥션이 없을 때 어떻게 동작할지를 지정한다. 1일 경우 maxWait 속성에서 지정한 시간만큼 커넥션을 구할 때 까지 기다리며, 0일 경우 에러를 발생시킨다. 2일 경우에는 일시적으로 커넥션을 생성해서 사용한다.
maxWaitwhenExhaustedAction 속성의 값이 1일 때 사용되는 대기 시간. 단위는 1/1000초이며, 0 보다 작을 경우 무한히 대기한다.
maxIdle사용되지 않고 풀에 저장될 수 있는 최대 커넥션 개수. 음수일 경우 제한이 없다.
minIdle사용되지 않고 풀에 저장될 수 있는 최소 커넥션 개수.
testOnBorrowtrue일 경우 커넥션 풀에서 커넥션을 가져올 때 커넥션이 유효한지의 여부를 검사한다.
testOnReturntrue일 경우 커넥션 풀에 커넥션을 반환할 때 커넥션이 유효한지의 여부를 검사한다.
timeBetweenEvctionRunsMillis사용되지 않은 커넥션을 추출하는 쓰레드의 실행 주기를 지정한다. 양수가 아닐 경우 실행되지 않는다. 단위는 1/1000 초이다.
numTestsPerEvictionRun사용되지 않는 커넥션을 몇 개 검사할지 지정한다.
minEvictableIdleTimeMillis사용되지 않는 커넥션을 추출할 때 이 속성에서 지정한 시간 이상 비활성화 상태인 커넥션만 추출한다. 양수가 아닌 경우 비활성화된 시간으로는 풀에서 제거되지 않는다. 시간 단위는 1/1000초이다.
testWhileIdletrue일 경우 비활성화 커넥션을 추출할 때 커넥션이 유효한지의 여부를 검사해서 유효하지 않은 커넥션은 풀에서 제거한다.


몇몇 속성은 성능에 중요한 영향을 미치기 때문에 웹 어플리케이션의 사용량에 따라서 알맞게 지정해주어야 하는데, 다음과 같이 고려해서 각 속성의 값을 지정하는 것이 좋다.

  • maxActive - 사이트의 최대 커넥션 사용량을 기준으로 지정. 동시 접속자수에 따라서 지정한다.
  • minIdle - 사용되지 않는 커넥션의 최소 개수를 0으로 지정하게 되면 풀에 저장된 커넥션의 개수가 0이 될 수 있으며, 이 경우 커넥션이 필요할 때 다시 커넥션을 생성하게 된다. 따라서 커넥션의 최소 개수는 5개 정도로 지정해두는 것이 좋다.
  • timeBetweenEvctionRunsMillis - 이 값을 알맞게 지정해서 사용되지 않는 커넥션을 풀에서 제거하는 것이 좋다. 커넥션의 동시 사용량은 보통 새벽에 최저이며 낮 시간대에 최대에 이르게 되는데 이 두 시간대에 필요한 커넥션의 개수 차이는 수십개에 이르게 된다. 이때 최대 상태에 접어들었더가 최소 상태로 가게 되면 풀에서 사용되지 않는 커넥션의 개수가 점차 증가하게 된다. 따라서 사용되지 않는 커넥션은 일정 시간 후에 삭제되도록 하는 것이 좋다. 보통 10~20분 단위로 사용되지 않는 커넥션을 검사하도록 지정하는 것이 좋다.
  • testWhileIdle - 사용되지 않는 커넥션을 검사할 때 유효하지 않은 커넥션은 검사하는 것이 좋다.

관련링크:



출처 - http://javacan.tistory.com/82






DB Connection Pool을 사용하기 위해서 Apache Commons의 dbcp를 많이 사용하고 있지만 매번 설정값에 대한 정확한 정의와 설정방법을 까먹는 경향이 있어 일반적인 설정값 가이드를 아주 간단히 정리하고자 한다. 

maxActive (최대 active connection 개수??)
  + 그냥 최대 Connection 개수로 생각하면된다.
  + 기본값은 8이며, 적당히? 설정하면 된다. 

minIdle
  + 사용되지 않고 풀에 저장될 수 있는 최소 커넥션 개수
  + 기본값은 0이며, 기본값을 사용하게 되면 connection pool이 비어버릴 수 있기 때문에 기본값 대신 적당한 설정이 필요하다. 
 

maxIdle
  + 사용되지 않고 풀에 저장될 수 있는 최대 커넥션 개수
  + 기본값은 8이며, 일반적으로 maxActive 개수와 동일하게 설정하는게 맞는 것 같다  
 

maxWait
  + connection 사용이 많아져서 connection pool이 비었을 때 대기시간 (단위 1/1000초)
  + 기본값은 -1(무한대)이며,  서비스 특성에 맞게 설정하면된다. 일반적으로 기본값을 사용해도 큰 문제는 안될 것 같다.
 

testOnBorrow 
  + connection pool에서 connection을 가져올 때 해당 connection이 유효성 검사 여부
  + 기본값은 false이며, 일반적으로 기본값을 사용한다. true설정하게 되면 매번 validationQuery를 수행하기 때문에 약간의 성능저하를 감수해야 한다.
 
 
testOnRetrun 
  + testOnBorrow와 비슷한데... 다만 유효성 검사 시점이 connection을 pool에 반환할때 이다.
 
 
timeBetweenEvictionRunsMillis 
  + 놀고 있는 connection을 pool에서 제거하는 시간기준 (설정된 시간동안 놀고 있는 connection을 minIdle&maxIdel 설정값을 고려하여 제거한다.)
  + 기본값은 -1이며, 단위는 1/1000초이다. 개인적으로 10분정도의 설정이 적당한 것 같다.
 
 
testWhileIdle 
  +  놀고 있는 connection의 제거 여부를 검사할 때 해당 connection의 유효성 테스트 여부
  + 기본값은 false이며, 일반적으로 true로 설정하는 것이 좋은 것 같다.
 
 
validationQuery 
 + connection 유효성 검사시에 사용할 쿼리문
  + DB 리소스를 최대한 적게 사용하는 쿼리를 사용하는게 좋다.
    예제)
      * Oracle : select * from dual 
      * MySql : select 1 
 
 
  

위의 설정 이외에도 추가적인 설정이 있지만, 지금까지 경험으로 봐서는 그닥 사용할 일이 없는 것 같아서 생략한다. (Simple is best!!!) 



출처 - http://dimdim.tistory.com/27







- 에러메시지 일부분

is longer than the server configured value of 'wait_timeout'.

 

- 문제 내용 및 해결책

IBATIS 커넥션 에러

 J2EE 개발 관련/IBATIS && MYBATIS 2012/03/22 08:46

시나리오 : was에 war를 배포하고 몇일이 지난후 갑자기 화면에 에러를 뿜으며 아래와 같은 메세지를 보여줬다. 제길.. 멍미.

에러 메세지

exception

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.dao.DataAccessResourceFailureException: SqlMapClient operation; SQL [];

--- The error occurred while applying a parameter map.

--- Check the aretias.category.selectChildCategorys-InlineParameterMap.

--- Check the statement (query failed).

--- Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 64,780,193 milliseconds ago. The last packet sent successfully to the server was 64,780,193 milliseconds ago. is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.; nested exception is com.ibatis.common.jdbc.exception.NestedSQLException:

--- The error occurred while applying a parameter map.

--- Check the aretias.category.selectChildCategorys-InlineParameterMap.

--- Check the statement (query failed).

--- Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 64,780,193 milliseconds ago. The last packet sent successfully to the server was 64,780,193 milliseconds ago. is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.

    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:656)

    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549)

    javax.servlet.http.HttpServlet.service(HttpServlet.java:617)

    javax.servlet.http.HttpServlet.service(HttpServlet.java:717)

    org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)

    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)

root cause

org.springframework.dao.DataAccessResourceFailureException: SqlMapClient operation; SQL [];

--- The error occurred while applying a parameter map.

--- Check the aretias.category.selectChildCategorys-InlineParameterMap.

--- Check the statement (query failed).

--- Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 64,780,193 milliseconds ago. The last packet sent successfully to the server was 64,780,193 milliseconds ago. is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.; nested exception is com.ibatis.common.jdbc.exception.NestedSQLException:

--- The error occurred while applying a parameter map.

--- Check the aretias.category.selectChildCategorys-InlineParameterMap.

--- Check the statement (query failed).

--- Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 64,780,193 milliseconds ago. The last packet sent successfully to the server was 64,780,193 milliseconds ago. is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.

    org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:104)

    org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)

    org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)

    org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)

    org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemplate.java:203)

    org.springframework.orm.ibatis.SqlMapClientTemplate.queryForList(SqlMapClientTemplate.java:293)

    com.aretias.jkholdings.repository.CategoryRepositoryImpl.selectChildCategorys(CategoryRepositoryImpl.java:22)

    com.aretias.jkholdings.service.CategoryServiceImpl.getChild(CategoryServiceImpl.java:19)

    com.aretias.jkholdings.controller.BaseController.getFirstDeptCategoryList(BaseController.java:42)

    com.aretias.jkholdings.controller.UserController.goLoginPage(UserController.java:23)

    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

    java.lang.reflect.Method.invoke(Method.java:597)

    org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:176)

    org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:426)

    org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:414)

    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790)

    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)

    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)

    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549)

    javax.servlet.http.HttpServlet.service(HttpServlet.java:617)

    javax.servlet.http.HttpServlet.service(HttpServlet.java:717)

    org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)

    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)


시나리오 환경 
- TOMCAT4.5 / JDK 5.0 / MYBATIS / SPRING 3.0 / DBCP

원인 
 - 마지막으로 DB에 커넥션을 맺은후 사용이 없다 보니 데이터 베이스 커넥션이 끝겼다. 

해결책
 - 특정 시간마다 커넥션을 확인 하는 셋팅을 지정한다. 

코드 

 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

<!-- DataSource Configuration -->

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">

        <property name="driverClassName" value="${jdbc.driverClassName}"/>

        <property name="url" value="${jdbc.url}"/>

        <property name="username" value="${jdbc.username}"/>

        <property name="password" value="${jdbc.password}"/>

        <property name="initialSize" value="5"/>

        <property name="maxActive" value="20"/>

        <property name="minIdle" value="5"/>

        <property name="maxWait" value="3000"/>

        <property name="poolPreparedStatements" value="true"></property>

        <property name="maxOpenPreparedStatements" value="50"></property>

           

        <!-- 특정 시간마다 validationQuery를 실행 셋팅 시작 -->

        <property name="validationQuery" value="select 1"/>

        <property name="testWhileIdle" value="true"/>

        <property name="timeBetweenEvictionRunsMillis" value="7200000"/>

        <!-- 특정 시간마다 validationQuery를 실행 셋팅 끝 -->

    </bean>

     

 

출처 - http://fbwotjq.tistory.com/entry/IBATIS-%EC%BB%A4%EB%84%A5%EC%85%98-%EC%97%90%EB%9F%AC

 





DB에 접속중인 세션을 오랫동안 사용하지 않거나, 네트워크에 문제가 발생하는 경우 DB 세션이 끊어질 수 있다.

DB 세션이 끊어지는 경우 App 입장에서는 재접속 처리를 해주어야 다시 정상적인 서비스가 가능해 진다.

 

재접속 처리 방법 중에 JDBC에 autoReconnect=true 옵션을 주는 방법이 있는데, 이 옵션을 잘못 사용하는 경우 얘기치 않은 문제가 발생할 수 있다.

autoReconnect 옵션은 쿼리를 수행한 다음 DB 세션에 문제가 있으면 단순히 SQLException 리턴 후 재접속 처리를 한다.

문제는 트랜잭션 구동 환경에서  수행중이던 트랜잭션은 롤백이 되어야 하고, 남은 트랜잭션은 수행이 되지 않아야 되는데, autoReconnect 옵션은 이런 처리를 해주지 않기 때문이다.

 

아래 예시는 3개의 쿼리로 이루어진 트랜잭션에서 첫번째 UPDATE 구문 실행후 DB 커넥션 종료 상황이다.

1개의 쿼리는 Rollback, 1개의 쿼리는 에러 리턴, 나머지 1개의 쿼리는 Commit 처리가 되면서 데이터 정합성이 깨지는결과를 초래하고 있다.

BEGIN;

UPDATE tb_work SET cnt = cnt+1 WHERE id = 10 ;

INSERT INTO tb_work_log VALUES (10, 20, 30) ;  # 커넥션 에러 발생 및 SQLException 리턴 후 재접속 (기존 UPDATE 쿼리는 자동 롤백)

DELETE FROM tb_work_list WHERE id = 10 ; # 새로운 세션에서 새로운 트랜잭션으로 진행됨

COMMIT ;

 

위와 같은 문제를 막기 위해서 autoReconnect=true인 환경에서는 SQLException이 발생하는 경우에, 해당 트랜잭션이 더 이상 진행되지 않도록 App 단에서 직접 예외 처리를 해줘야 하고, MySQL 레퍼런스 메뉴얼에서도 autoRecoonect 옵션 사용은  권장하지 않고 있다.

http://dev.mysql.com/doc/refman/5.0/en/connector-j-reference-configuration-properties.html

 

Property Name

Definition

Default Value

Since Version

autoReconnect

Should the driver try to re-establish stale and/or dead connections? If enabled the driver will throw an exception for a queries issued on a stale or dead connection, which belong to the current transaction, but will attempt reconnect before the next query issued on the connection in a new transaction. The use of this feature is not recommended, because it has side effects related to session state and data consistency when applications don't handle SQLExceptions properly, and is only designed to be used when you are unable to configure your application to handle SQLExceptions resulting from dead and stale connections properly. Alternatively, investigate setting the MySQL server variable "wait_timeout" to some high value rather than the default of 8 hours.

false

1.1

 

트랜잭션을 사용하는 환경이라면 DB 세션의 재접속 처리는 JDBC의 autoReconnect 설정이 아닌 DBCP의 validationQuery 기능을 사용하는 것이 적합하다.

DBCP 설정 관련 apache 문서 : http://commons.apache.org/dbcp/configuration.html

 

출처 - http://blog.naver.com/PostView.nhn?blogId=seuis398&logNo=70118975290

 






 

dbcp pooling설정에 validationQuery적용

tomcat dbcp 이용하여 검색데이터 추출할 , mysql 사용

mysql wait_timeout
설정(기본값 28800 , 8시간) 의해 커넥션이 연결된 이후 해당 

커넥션의 close 없이 8시간이 지나면 해당 커넥션을 종료.


issue : 종료된 커넥션을 dbcp connection pool 에선 여전히 가지고 있는 상태.

이런 상황에서 DB 관련 프로그램이 호출되면 커넥션 관련 에러가 발생.

solution : java에서 DB 사용하기 전에 해당 connection 정상적인지 검사를 하도록 하는 .
옵션이 validationQuery.

<-bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"->
<-property name="driverClassName" value="${jdbc.driverClassName}"/->
<-property name="url" value="${jdbc.url}"/->
<-property name="username" value="${jdbc.username}"/->
<-property name="password" value="${jdbc.password}"/->
<-property name="validationQuery" value="select 1"/->
<-/bean->

<-Resource name="jdbc/livesearch" auth="Container"
type="javax.sql.DataSource"
maxActive="10" maxIdle="30" maxWait="10000"
username="${jdbc.username}" password="${jdbc.password}"
driverClassName="com.mysql.jdbc.Driver"
url="${jdbc.url}"
validationQuery="select 1"
/>

같이 사용하면 된다.

<
참고>
오라클의 경우 : validationQuery="select 1 from dual"


출처blog.hoonie.net

전에 기록한 "DBCP validationQuery 약인가? 독인가?"에서 validationQuery 필수가 아니라고 했었다. 그렇다면 만약 DBCP에서 바라보고 있는 DB 서버가 어떠한 이유로 사용 불가 상태에 들어갔다가 다시 사용 가능해 진다면 validationQuery 없어도 DBCP Connection Pool 제대로 복구할까?

DBCP
공식 사이트에서 관련된 내용을 검색해 보니 DBCP 검증기능을 사용하지 않는 경우에도 DB서버가 셧다운 되었다가 다시 기동되면 자동으로 새로운 Connection 객체들을 Pool 로딩한다 한다

, DBCP 프러퍼티를 기본값으로 설정되어 있고, 사용하는 JDBC 드라이버가 select 등의 쿼리 실행시 발생하는 예외상황에 대해 SQLException 제대로 보고한다는 전제하에 굳이 validationQuery 사용하지 않아도 된다고 한다. 적어도 최근 버전의 DBCP에서는 validationQuery 돌다리도 두드려보는 개념인것 같다

다음은 DBCP사이트의 Wiki(DBCP공식사이트) 에서 확인한 내용이다.

Q: Without using validation of connections (testOnBorrow = false, testOnReturn = false, timeBetweenEvictionRunsMillis = -1) and after shutdown and restarting the database again, it looks like the pool is cleaning its old connections by itself. So it turns out that we always have valid connections. How can you explain this and when is explicit validation necessary? 

A: During the connection activation (when borrowing a connection) the setAutoCommit and other connection init methods are called. If one of these methods throws a SQLException then the connection is also considered broken and removed from the pool. 

So if you are using one of the "default*" properties and the JDBC driver correctly reports the SQLExceptions on the "set*" methods then you don't need an extra validationQuery.

참고 사이트Apache commons DBCP SITE

<
참고 이미지>

Posted 12th October 2009 by 김형구








mysql wait_timeout 설정(기본값 28800 , 8시간) 에 의해 커넥션이 연결된 이후 해당

커넥션의 close 없이 8시간이 지나면 해당 커넥션을 종료 시키게 된다.

   

문제는 이렇게 종료된 커넥션을 dbcp의 connection pool 에선 여전히 가지고 있는 상태라는 것이다.

이런 상황에서 DB 관련 프로그램이 호출되면 커넥션 관련 에러가 발생된다.

   

해결방법은 java에서 DB를 사용하기 전에 해당 connection 이 정상적인지 검사를 하도록 하는 것이다. 이 옵션이 validationQuery 파라메터이다.

   

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
  <property name="driverClassName" value="${jdbc.driverClassName}"/>
  <property name="url" value="${jdbc.url}"/>
  <property name="username" value="${jdbc.username}"/>
  <property name="password" value="${jdbc.password}"/>
  <property name="validationQuery" value="select 1"/>
 </bean>

 

http://blog.naver.com/PostView.nhn?blogId=pignbear&logNo=150037833102&redirect=Dlog&widgetTypeCall=true

 




 

운영툴 에러 발생.. 로그는 아래와 같다..


에러로그:

com.mysql.jdbc.exceptions.jdbc4.CommunicationsException:
 ...., which  is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.


자상하게도 autoReconnect=true 바꾸거나 wait_timeout 수정하라고 한다..

wait_timeout connection 증가로 그리 땡기진 않고..autoReconnection 추가하기로 했다.
설정은 jdbc 커넥션 설정 파일에서 url "autoReconnection=true" 넣어주면 된다.

* url=jdbc:mysql://ip:port/dbname?useUnicode=true&characterEncoding=utf8&autoReconnect=true

* validationQuery="select 1"


그리고 외에도 validationQuery 넣어주는 이유는 한번 커넥션이 끊어진다음 재시도를 하는 경우 문제가 있는 처음 한번의 시도는 에러가 나게 된다. 이때 넣어주는게 validationQuery 모든 사용자쿼리를 실행 전에 한번 쿼리를 실행하게 된다.(그러므로 DB로서는 추가적인 부하가 ) 쿼리가 한번 실행되는 것인 만큼 가장 간단한 쿼리여야 한다.

>validationQuery description

Parameter

Default

Description

validationQuery

 

The SQL query that will be used to validate connections from this pool before returning them to the caller. If specified, this query MUST be an SQL SELECT statement that returns at least one row.

 



보통은 SELECT 1 많이 쓴다.(oraqle SELECT 1 FROM DUAL)
추가적인 쿼리인 만큼 access 많은 곳에선 조심해서 써야 할듯?

jdbc 설정과 관련된것은 아래 링크를 참조함..
http://commons.apache.org/dbcp/configuration.html


출처 - http://netholic.tistory.com/137









DBCP의 validationQuery 약인가? 독인가?


출처 : http://www.hoonie.net/blog/64

현재 담당하고 있는 프로젝트와 Apache의 Commons에 있는 DBCP를 사용하여 구현된 Connection Pool 관리자로부터 Connection을 받아서 쓰고 있다. 그런데 DB 서버의 부하를 점검해 본 결과, 당연하게도 DBCP의 validationQuery로 할당한 SQL문의 호출이 가장 많았다.
솔루션의 성격상 DB 서버에 대한 Access가 빈번히 일어나고 그 응답 또한 빠른시간을 필요로하기 때문에 DB의 부하를 가능한 줄여야 하는데 DBCP에서 Connection 객체를 받아 올 때 마다 실행되는 validationQuery는 엄청난 부하를 야기하고 있었다. 값비싼 객체인 DB와의 Connection을 효율적으로 관리하여 DB 관련 프로세스의 효율을 높이고자 사용하는 DBCP가 아이러니하게도 DB 서버의 부담을 높이는 작용을 하고 있었던 것이다.
과연 validationQuery는 반드시 필요한가? DBCP의 API 문서를 확인한 결과, BasicDataSource의 Validation Query는 필수가 아닌 선택적인 기능으로서 할당되었을 경우에만 수행되는 것으로 나와 있다. 단, 이 기능을 사용하고자 할당한 경우에는 해당 쿼리의 실행결과 반드시 1개 이상의 resultset이 나와야 한다고 명시되어 있다.
만약 자신의 프로젝트에서 DBCP를 사용하고 있다면, 그리고 validationQuery를 설정하여 사용하고 있다면 해당 쿼리가 최경량의 SQL문을 사용하고 있는지 확인하는 것은 잊지 말아야 할 것이다.
추천되는 쿼리는 Oracle의 경우

select 1 from dual;

MySQL의 경우

select 1;

정도를 사용하면 좋을 것이다. 이외의 쿼리를 validationQuery로 사용 중 이라면 지금 당장 쿼리 실행 소요 시간을 비교해 보라. 

[출처] DBCP의 validationQuery 약인가? 독인가?|작성자 빛나리

 






timeBetweenEvctionRunsMillis - 사용되지 않는 커넥션을 추출하는 쓰레드의 실행 주기를 지정

이값을 알맞게 지정해서 사용되지 않는 커넥션을 제거하는것이 좋다 보통 10~20분 단위 검사

 

testWhileIdle - true 일 경우 비활성화 커넥션을 추출할때 커넥션이 유효한지 여부를 검사해서 유효하지 않으면 제거

[출처] 트랜잭션 , 컨넥션 풀 관련|작성자 김상현

 







Batis, DBCP, MySQL 을 사용하는 웹어플리케이션 구동 중, 일정 시간 동안 컨넥션을 사용하지 않다가 사용을 하면 컨넥션이 이미 종료 되었다고 나타나는 문제가 발생했다.

   

Communications link failure due to underlying exception

뭐 사실 .. 어느 정도 사용을 하는 어플리케이션이라면 이런 문제는 발생하지 않을거다.
MySQL 은 기본적으로 컨넥션을 통해서 8시간 동안 request가 오지 않는다면, 강제적으로 컨넥션을 닫아버린다.
( 이는 물론 MySQL 의 설정을 변경함으로써 값을 바꿀 수는 있다. 하지만, 좋은 방법이라고 생각되지는 않는다. )

다음과 같은 iBatis 설정에서도 당연히 동일한 문제가 발생했다.

  <dataSource type="DBCP">
   <property name="JDBC.Driver" value="com.mysql.jdbc.Driver" />
   <property name="JDBC.ConnectionURL" value="jdbc:mysql://데이터베이스접속url?autoReconnect=true" />
   <property name="JDBC.Username" value="id" />
   <property name="JDBC.Password" value="password" />
   <property name="JDBC.DefaultAutoCommit" value="true" />
   <property name="Pool.MaximumActiveConnections" value="5" />
   <property name="Pool.MaximumIdleConnections" value="3" />
   <property name="Pool.MaximumWait" value="60000" />
  </dataSource>


다음과 같이 설정값을 변경함으로써 해당 문제를 해결 할 수 있다.

  <dataSource type="DBCP">
   <property name="driverClassName" value="com.mysql.jdbc.Driver" />
   <property name="url" value="jdbc:mysql://데이터베이스접속url?autoReconnect=true" />
   <property name="username" value="id" />
   <property name="password" value="password" />
   <property name="defaultAutoCommit" value="true" />
   <property name="maximumActiveConnections" value="5" />
   <property name="maximumIdleConnections" value="3" />
   <property name="maximumWait" value="60000" />
   <!-- validationQuery:유효 검사용 쿼리( 1개 이상의 row를 반환하는 쿼리를 넣어주면 된다. ) --> 
   <property name="validationQuery" value="select 1"/>
   <!-- testWhileIdle:컨넥션이 놀고 있을때 -_-; validationQuery 를 이용해서 유효성 검사를 할지 여부. -->
   <property name="testWhileIdle" value="true"/>
   <!-- timeBetweenEvictionRunsMillis:해당 밀리초마다 validationQuery 를 이용하여 유효성 검사 진행 -->
   <property name="timeBetweenEvictionRunsMillis" value="7200000"/>
  </dataSource>


이렇게 설정하면 컨넥션을 풀에서 가지고 올때도, validationQuery 를 통해서 유효성 검사를 진행하게 되는데,
뭐 퍼포먼스가 문제 될거라고 생각된다면 -_-aa .. testOnBorrow( default : true ) 값을 false 로 추가해주면 된다.

설정값의 테스트는 mysql 의 show processlist; 쿼리를 이용하여 정상적으로 구동되는지 알 수 있다.
show processlist 를 수행하면 현재 mysql 에서 수행되고 있는 프로세스의 리스트와 상태를 알 수 있는데,
웹어플리케이션을 구동하고, 컨넥션이 맺어지도록 한 후에 해당 프로세스가 command 필드가 sleep 상태에서 Time 필드 값이 timeBetweenEvictionRunsMillis/1000 보다 커지지 않는다면, 정상적으로 설정된 것이다. ( 뭐 물론 약간의 차이는 날 수 도 있겠으며, 해당 테스트 동안 컨넥션이 사용된다면 잘못 나타날 수 도 있다. ) 약 1,000 정도의 값으로 셋팅을 하고 테스트 후 적절한 값을 넣어서 사용하면 되겠다.

그 외에도 이상의 문제를 해결 할 수 있는 설정은 몇가지가 더 있다.
http://commons.apache.org/dbcp/configuration.html 를 참고 하면 된다.

 

출처 - http://blog.daum.net/iccaruss2/7501371

 






 

DBCP (Database connection pooling services)

  • 1.1 DBCP configuration

  • DBCP BasicDataSource

    iBATIS SimpleDataSource

    Option

    description

    driverClassName

    JDBC.Driver

    required

    JDBC driver class

    url

    JDBC.ConnectionURL

    required

    DB Connection URL

    username

    JDBC.Username

    optional

    UserName

    password

    JDBC.Password

    optional

    Password

    maxActive

    Pool.MaximumActiveConnections

    optional

    최대 커넥션 (Maximum Active Connections)

    initialSize

    Pool.MinimumIdleConnections

    optional

    최초 초기화 커넥션

    maxIdle

    Pool.MaximumIdleConnections

    optional

    사용되지 않고 풀에 저장될 있는 최대 커넥션 개수. 음수일 경우 제한이 없음.

    minIdle

    Pool.MinimumIdleConnections

    optional

    사용되지 않고 풀에 저장될 있는 최소 커넥션 개수

    maxWait

    Pool.MaximumWait

    optional

    최대 대기시간(milliseconds). 음수일 경우 제한이 없음

    validationQuery

    Pool.ValidationQuery

    optional

    Validation Query

    testOnBorrow

      

      

    true 경우 커넥션을 가져올 커넥션이 유효한지의 여부를 검사.

    testOnReturn

      

      

    true 경우 커넥션을 반환할 커넥션이 유효한지의 여부를 검사.

    testWhileIdle

      

      

    true 경우 유효하지 않은 커넥션은 풀에서 제거

    timeBetweenEvictionRunsMillis

      

      

    사용되지 않은 커넥션을 추출하는 쓰레드의 실행주기를 지정. ( 음수이면 동작하지 않음, milliseconds)

    numTestsPerEvictionRun

      

      

    사용되지 않은 커넥션을 검증할 connection 지정

    minEvictableIdleTimeMillis

      

      

    pool 대기중인 시간이 설정된 값보다 크다면 validationQuery 관계없이 풀에서 제거

    1.2 connection validation check

    <validationQuery>select 1</validationQuery>
    

    <testOnBorrow>false</testOnBorrow>
    

    <testWhileIdle>true</testWhileIdle>
    

    <numTestsPerEvictionRun>1</numTestsPerEvictionRun>
    

    <timeBetweenEvictionRunsMillis>3000</timeBetweenEvictionRunsMillis>
    

     

    출처 - http://hermeslog.tistory.com/132

     

     


'DB > Common' 카테고리의 다른 글

NoSQL 소개  (0) 2012.05.18
SQL 구문 기본 작성 가이드  (0) 2012.05.08
CREATE SCHEMA  (0) 2012.04.12
join & view  (0) 2012.04.10
제로보드로 유료 사이트 만들기 (결제 테이블)  (0) 2012.04.09
Posted by linuxism
,

CSS 개요

Development/CSS 2012. 4. 30. 09:18


웹 문서의 전반적인 스타일을 미리 저장해 둔 스타일시트이다. 문서 전체의 일관성을 유지할 수 있고, 세세한 스타일 지정의 필요를 줄어들게 하였다.

기존의 HTML은 웹 문서를 다양하게 설계하고 수시로 변경하는데 많은 제약이 따르는데, 이를 보완하기 위해 만들어진 것이 스타일 시트이고 스타일 시트의 표준안이 바로 CSS 이다. 간단히 스타일시트라고도 한다.

HTML을 이용해서 웹 페이지를 제작할 경우 전반적인 틀에서 세세한 글꼴 하나 하나를 일일이 지정해주어야 하지만, 웹 페이지의 스타일(작성형식)을 미리 저장해 두면 웹 페이지의 한 가지 요소만 변경해도 관련되는 전체 페이지의 내용이 한꺼번에 변경되므로, 문서 전체의 일관성을 유지할 수 있고 작업 시간도 단축된다.

따라서 웹 개발자들은 보다 풍부한 디자인으로 웹을 설계할 수 있고, 글자의 크기, 글자체, 줄간격, 배경 색상, 배열위치 등을 자유롭게 선택하거나 변경할 수 있으며 유지·보수도 간편하게 할 수 있다.

각기 다른 사용자 환경에서 동일한 형태의 문서를 제공한다는 이점도 있다. CSS로 만들어진 문서는 사용자들의 브라우저 환경에 따라 홈페이지가 다르게 나타나는 일이 없고 어느 환경에서나 제작자가 의도한대로 그 효과가 전달된다.

출처 - 네이버

======================================================================

CSS 또는 캐스케이딩 스타일 시트(Cascading Style Sheet)는 마크업 언어가 실제 표시되는 방법을 기술하는 언어로, HTMLXHTML에 주로 쓰이며, XML에서도 사용할 수 있다. W3C의 표준이며, 레이아웃과 스타일을 정의할 때의 자유도가 높다.

목차

  [숨기기

[편집]CSS 버전의 변화

CSS는 지속적으로 새로운 버전이 나오고 있다. 1996년에 도입된 CSS 1은 CSS의 바탕이 되었다. CSS의 표준으로는CSS 2.1이 있으며 이전 버전에 비하여 새로운 기능과 도구가 추가되었다. 대다수의 웹브라우저는 CSS 2.1를 잘 지원한다.(인터넷 익스플로러의 경우, 버전 7이 되면서 CSS2.1을 지원한다.) 현재 W3C에서는 CSS3을 표준으로 만들고 있다.

CSS는 여러 수준과 프로파일을 가지고 있다. 각 수준의 CSS는 일반적으로 새로운 기능을 담고 있으며 CSS1, CSS2, CSS3로 나뉜다. 프로파일들은 일반적으로 특정한 장치나 사용자 인터페이스를 위해 만들어진 하나 이상 수준의 CSS의 하부 집합이다. 현재 휴대용 장치, 프린터, 텔레비전 수상기를 위한 프로파일들이 있다.

[편집]CSS1

첫 CSS 규격은 공식 W3C 권고안이 되었으며 그 이름은 CSS1이다. 1996년 12월에 출시되었다.

[편집]CSS2

CSS2는 W3C가 개발하였으며 1998년 5월에 권고안으로 출시되었다.

[편집]CSS3

CSS3는 2005년 12월 5일 이후 개발 중에 있다.[1] W3C CSS3 로드맵은 요약과 도입부를 제공하고 있다.[2] 전체가 모듈화 되어 사용자 에이전트가 모듈에 대한 모든 모듈을 지원하지 않거나 자유롭게 선택할 수 있도록 하고 있으며, 다른 세로 글쓰기와 HTML 이외의 규격에 까지 관여하는 내용으로 되어 있다. 현재 어떤 모듈도 권고안까지 이른 것은 없다.

[편집]같이 보기

[편집]주석

  1.  W3CCSS: under construction, CSS 3
  2.  Introduction to CSS3, W3C Working Draft, 23 May 2001

[편집]바깥 고리



===================================================================================

Cascading Style Sheets (CSS, 캐스케이딩 스타일 시트, CSS 스타일 시트)는 HTML 이나 XML 요소를 어떻게 수식 (표시)하거나 지시하는 W3C 에 의한 사양의 하나. 문서의 구조 와 체계 를 분리 시킨다는 이념을 실현하기 위해 제창되었다 스타일 시트 의 구체적인 사양의 하나.

CSS는 HTML로 표현 가능하다고 생각되는 디자인의 대부분을 실현할 수있는 요소를 도입하면서, 새로운 디자인 기능을 갖춘다. 또한 다음과 같은 특징을 가진다.

  • 페이지를 표시하는 미디어에 맞는 스타일 시트를 전환하면 미디어 당을 변화시킬 수있다
  • 사용자 에이전트 (대부분의 경우 웹 브라우저 ), 웹사이트 제작자, 사용자가 각각 정의한 CSS가 가져오는 효과를 쌓는다 (캐스케이드) 할 수

그러나 확장 및 수정이 계속되고있다 CSS 사양 모두를 완전하게 구현하는 사용자 에이전트는 사실상 전혀 없다고 잘 실제 점유율 다수를 차지하는 사용자 에이전트는 부분 대응에 불과하다. 그러나 실용상 지장이없는 수준 구현되어 왔으며, 게다가 표현 서로 호환성도 고려되고있다.

CSS는 1994 년 에 WWW 탄생 지인 CERN 에 근무하는 하콘 위우무 리 씨에 의해 제창되었다.

목차

  [ 숨기기 ] 

작성 편집 ]

스타일 정보는 읽을 내용 (작성자 스타일 시트)와 사용자 에이전트 설정 (스타일 시트)의 두 군데에 기재할 수있다. 또한 사용자 에이전트가 자신의 스타일 (기본 스타일 시트)를 가지고있다.

만든 스타일 시트는 태그 문서에 직접 작성하거나 다른 문서로로드하는 형태로 이용된다. CSS의 편의를 최대한 발휘하기 위해, 다른 문서로로드하는 것이 추천되고있다.

작성 방법 편집 ]

여기에서 CSS Level 2에 대해 설명한다. CSS의 문법은 다른 레벨 사이에서도 호환성을 갖도록 설계되었으며, 예를 들어 CSS Level 1로 작성된 스타일 시트를 CSS Level 2로 취급도 가능하다 (단 일부 해석의 차이 등 에 따른 호환성 부분도 존재한다). CSS는 요소에 스타일을주기 위하여 다음과 같은 사양이 정해져있다.

다음 CSS 조각을 예로 들면.

p # id  {  color  :  # ff3300  }
  • "{"부터 "}"까지의 부분을 선언 블록 이라는
  • "p # id"를 선택 (선택자)라고 스타일이 적용되는 대상을 나타내는
  • 선언 블록과 선택을 맞춰 규칙 집합 이라는
  • "color : # ff3300"부분을 선언 한다
  • 선언에서 ":"이전 (위 예제에서는 "color")를 속성 (특성)는
  • 선언에서 ":"다음 (위 예제에서는 "# ff3300")를 값을 는

위에 예제 CSS 조각을 적용하겠다고 선언하고있는 문서 중 선택이 지정하는 것과 일치하는 부위 (HTML 문서에서 요소 요소의 부모와 자식 관계, 특정 클래스 ID)에 선언 블록 의 선언이 적용된다. 선언은 "속성 : 값"또는 "하늘 (아무것도 쓰지 않는다)"중 하나로 구성되어 속성 ":"값 앞뒤에 공백 문자 (공백, 탭, 개행)를 자유롭게 넣어져 또한 ";"으로 구분하여 선언 나란히 쓸 수있다.

위에 예제는 HTML 문서에 적용하려면 "id라는 ID를 가진 p 요소의 글자색을 빨간색 FF (= 255), 녹색 33 (= 51), 파랑 0하라"는 지정을 의미한다.

color  :  # ff3300 ; 
width  :  35 %
color  :  "# 0033ff" ; 
width  :  '53 % '

이러한 선언이 있었을 때, 후자 두가지는 ""와 ''를 붙여 때문에 부정하다. 왜냐하면, ""나 '안에있는 것은 문자열로 취급되고 color 속성이 취할 수있는 색상 값 (# rrggbb, rgb (0-255], [0-255], [0-255) 또는 black과 red와 같은 키워드 등)가 없기 때문이다.

p # id  {  color :  # ff3300  } 
p # id  {  font-size :  24px  }

p # id  {  color :  # ff3300 ;  font-size :  24px  }

와 동일하다. ;은 전자와 같이 선언을 선택기에 하나씩 써있는 것을 하나의 선택 블록 작성할 때 선언을 나누는데 사용한다. 따라서 반드시 선언;를 붙이는 것을 강제하는 것은 아니다.

선택기 구현 수준 높은 브라우저라면 어떤 속성도 CSS를 적용하는 것이 가능하며,이 경우 ID에 대한 속성 선택이기 때문에, # id는 [id = "id"]와 동일하다 . 선택기 간단한 매칭이 가능하다. 다른 HTML 태그에 적용 문서 구조에서 본 아이 · 남매 구조에 적용 선택, 나아가서는 링크와 동적 표현과 언어에 대한 의사 클래스 (: link, : hover, : lang) 등이있다.

우선 순위 편집 ]

CSS는 반드시 한 곳에서 고유하게 지정할 수 않으므로 지정 내용 충돌을 피하기 위해 우선 순위가 사용자 에이전트에 의해 계산된다. 그 결과는 다음과 같은 조건에 따라 산출된다.

  • 만든 스타일 시트는 사용자 스타일 시트보다 우선합니다.
  • 기본 스타일 시트는 다른 스타일 시트를 우선
  • 가장 중요한 지정하는 선언은 CSS가 만든 스타일 시트보다 우선 (CSS1에서는 반대)
  • 외부에서 가져온 것은 가져온 대상 정리해 취급
  • 상세도에 따라 정리
    • 그 선택에 지정된 위치를 고유하게 결정되는 것 (ID의 종류)이 많은 분들을 우선하는
    • ID의 종류에 의한 우선 순위가 같은 경우는 속성과 유사 클래스의 수가 많은 쪽을 우선하는
    • 그래도 우선 순위가 같을 경우 요소의 수가 많은 쪽을 우선하는
  • 그래도 아직 우선 순위가 동일한 경우 제작자 스타일 시트에서 아래의 순서로 우선하는
    1. 인라인 것
    2. 외부에서 온
  • HTML의 align 속성과 같은 CSS 이외에 의하면 스타일 지정은 해당하는 CSS의 스타일 지정이 제작자 스타일 시트의 시작에있는 것으로 취급한다. 그러나 이러한 내용도 가장 낮은 것으로한다 (CSS1에서는 요소 이름에 의한 지정을 하나만 포함한 셀렉터와 같은 세부 사항 수준)

설명 가능한 방법은 다음과 같다 일반적으로 선호하는 순위로 정렬한다 (CSS2에 가장 중요한 지정의 우선 순위 사양이 변경되고, 권고 6 장 4).

  1. 사용자 스타일 시트 중 가장 중요한 지정된 선언 - 사용자 에이전트 설정 스타일에! important를 선언 추가하기
  2. 만든 스타일 시트 중 가장 중요한 지정된 선언 - 작성자가 내용에 부수시킨 스타일에! important를 선언에 추가한다.
  3. 만든 스타일 시트의 일반 선언
  4. 사용자 스타일 시트의 일반 선언
  5. 기본 스타일 시트 선언

만든 스타일 시트를 작성하는 방법에 의한 우선 순위는 다음과 같다.

  1. 특정 요소에 스타일을 설명하는
  2. HTML과 XML의 헤더 부분에 그 페이지 전체를 대상으로 스타일을 정의하는
  3. CSS만을 설명하는 외부 파일을 준비하고, HTML 파일의 헤더 부분에서 링크되어 스타일을 참조하는


권고 등 편집 ]

CSS 사양은 수준이라는 단계를 갖고, 2011 년 11 월 단계에서, Level 1에서 Level 4까지 사양이 공개되고있다.

Cascading Style Sheets, level 1 (CSS1) 권고 1996 년 12 월 편집 ]

박스 모델의 참고 그림

여백

국경

패딩

내용

패딩

국경

여백

박스에 width 속성을 설정했을 때, W3C 의 박스 모델은 내용의 가로로 해석된다. 그리고 패딩과 보더 분 너비 요소의 너비에 추가된다.

한편 마이크로 소프트 박스 모델은 width 속성은 내용의 너비와 패딩과 보더 분을 더한 것, 즉 요소 모든 가로된다 [1] . 따라서 Internet Explorer5.5 이하와 6.0 이상 및 Internet Explorer 이외의 Web 브라우저에 표시 차이를 접근하기 위해서는 패딩과 보더를 0으로 또는 CSS 핵 을 사용해야합니다.

Internet Explorer 6에서는 DOCTYPE이 정확하다면 표준 모드로 전환 가능 (단 XML이나 XHTML의 경우 XML 선언을 사양대로 쓰면 과거 호환 모드 로 렌더링되는 버그가있다).

Cascading Style Sheets, level 2 (CSS2), 권고 1998 년 5 월 편집 ]

CSS2는 CSS1의 상위 호환. 몇 가지 개념을 추가 · 확대 · 개정이 이루어졌다.

구체적으로 표시 매체 (모니터와 TV, 종이 매체 등)에 따라 자동으로 스타일 시트를 변경할 수 있도록하고 그에 부수하여 음성 브라우저 에 대한 대응, 인쇄 매체에 대한 대응이 이루어 글꼴 등의 표시 기능을 확장하고 상자 개념의 수정이 이루어졌다.

그러나 2002 년경 이후에 발표된 CSS 지원 UA에서이를 사양으로 간주하고있는 것은 존재하지 않고, 실질적으로 CSS2.1의 사양 역할을 맡긴 모양으로되어있다. CSS2 권고 사양에 액세스하면 CSS2 관리되지 않고 사양 참조 및 구현은 CSS 2.1을 기반으로하라고 장려하는주의 사항이있다.

Cascading Style Sheets, level 2 revision 1 (CSS 2.1), 권고 2011 년 6 월 편집 ]

CSS2의 개정판. CSS2 규격의 정의가 불명확 있었기 때문에 각 사용자 에이전트 CSS2 구현 비호 환성 문제가 발생했기 때문에, 애매한 설명을 명확하게하는 등의 개정이 이루어졌다. 또한 text-shadow 속성과 같이 CSS2에 책정되어 있으면서 오랫동안 구현이 이뤄지지 않은 것, display 속성 run-in 값을 여러 사용자 에이전트 상호 운용성을 확보하지 못한 기능이 제거됩니다. 그들은 CSS3 이후 수준에서 정의된 다시하게된다.

CSS 구현시 업체는 2002 년경부터 CSS2.1를 기본 사양으로 간주하고있다.

Cascading Style Sheets, level 3 (CSS3) 편집 ]

CSS3 이후 전체가 모듈화 되어 사용자 에이전트가 모듈을 지원하는 어떤 모듈을 지원하지 않거나 자유롭게 선택할 수 있도록하는 다른 세로 서 자와 HTML 이외의 규격에까지 관여 내용과 되고있다. 2011 년 11 월 현재 권고되고있는 모듈은 다음과 같다.

Cascading Style Sheets, Level 4 (CSS4) 편집 ]

CSS4는 CSS3와 마찬가지로 모듈화된있다. CSS4 모듈 추가하는 기능은 CSS3 정의되지 않은했던 새로운 기능 외에도 CSS3 모듈에 한 번 포함되면서 상호 운용성을 충분히 확보하지 못하고 사양에서 생략 기능으로 구성된다. 2011 년 11 월 현재, 셀렉터 사양 Level 4가 유일한 공개 초안으로 공개되고있다.

이 절은 쓰기 도중에 이 절은 집필 합니다. 가필 정정 해 주시 협력자를 찾고 있습니다 .

각주 · 출전 편집 ]

  1. en : Internet Explorer box model bug

관련 항목 편집 ]

외부 링크 편집 ]










'Development > CSS' 카테고리의 다른 글

CSS - 버튼  (0) 2012.05.14
CSS - 정리  (0) 2012.05.13
CSS - em 단위  (0) 2012.05.13
CSS - 글자 레이아웃 속성  (0) 2012.05.12
CSS - background-repeat  (0) 2012.05.10
Posted by linuxism
,

같은 패키지 내의 File 을 상대 경로로 가져오기

발생일: 2009.08.07

문제:
현재 클래스와 같은 패키지(폴더)에 있는 파일을 읽어오려고 한다.
상대 경로로 접근해서 가져오려고 하는데,
new File("./test.txt"); 와 같이 상대 경로로 접근하니 정상적으로 불러지지 않는다.

해결책:
자바의 File 에서 사용되는 상대 경로의 기준은는 일반적으로 우리가 생각하는 것처럼
해당 클래스 파일이 있는 위치가 아니라,
클래스 파일이 포함되어 있는 프로젝트 폴더이다.

예를 들어,
클래스를 하나 생성하고

    File path = new File(".");
    System.out.println(path.getAbsolutePath()); //--> 프로젝트 폴더의 주소가 출력됨

위와 같이 현재 클래스 위치에서 폴더를 생성하여 절대 주소를 출력해보면 프로젝트 폴더의 주소가 출력된다.


현재 클래스와 같은 패키지 또는 폴더 내의 파일을 읽어오려면,
Class 또는 ClassLoader 의 getResource 를 사용하여 아래와 같은 방법으로 사용할 수 있다.
(현재 클래스명이 FileTest 라고 가정한다)

    String path = FileTest.class.getResource("").getPath(); // 현재 클래스의 절대 경로를 가져온다.
    System.out.println(path); //--> 절대 경로가 출력됨
    File fileInSamePackage = new File(path + "test.txt"); // path 폴더 내의 test.txt 를 가리킨다.


위에서 path 는 현재 클래스의 절대 경로를 가져오며,
가져온 경로를 포함하여 같은 폴더 내의 다른 파일에 접근할 수 있다.

출처 - http://ohgyun.com/tag/File


'Development > Java' 카테고리의 다른 글

printstacktrace와 log4j  (0) 2012.05.03
자바에서 인코딩(encoding)  (0) 2012.05.03
Java 암호화 구현  (0) 2012.04.28
정보시스템 SW 개발보안(시큐어 코딩 secure coding) 가이드  (0) 2012.04.25
Dead code  (0) 2012.04.19
Posted by linuxism
,