2013년 12월 19일 목요일

No operations allowed after connection closed 오류 해결

com.mysql.jdbc.exceptions.MySQLNonTransientConnectionException: No operations allowed after connection closed.

com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was ? milliseconds ago. The last packet sent successfully to the server was ? 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:


Java(Spring)  + MySQL 환경에서 이런 식의 오류가 발생하는 경우가 있다.

원인 Exception을 따져보면 
MySQL DB 커넥션(세션)이 너무 오랫동안 미 사용이라서 커넥션이 강제 해제 당했다고 인식하면 되겠다.
(네크워크가 끈기는 경우도 있으나, 이럴 경우는 에러 메세지가 다르다) 궁극적으로 MySQL 설정에 따른 오류가 발생한 것이라고 인식하면 된다 (WAS DataSource, JDBC 드라이버, MySQL 서버 문제나 오류는 아니다.)
MySQL 기본 설정은 8(28800)시간동안 DB 연결이 없을 경우에는 세션을 해제하도록 되어있다.

그러면서 mysql-jdbc 설정에서 autoReconnect=true 를 설정하라고 되어있다.

MySQL 관련 문서 링크
http://dev.mysql.com/doc/refman/5.0/en/connector-j-reference-configuration-properties.html

잡설은 이정도로 하고 해결방안을 알아보면 3가지 방법 정도가 있겠다.

1. MySQL wait_timeout 값을 올린다.
   MySQL console 에서 Set GLOBAL wait_timeout = 숫자; 로 설정하거나, /etc/my.cnf 파일을 수정하면 된다.

2. JDBC 커넥션 설정 시 autoReconnect옵션을 활성화 시킨다.
    jdbc:mysql://ip:port/dbname?autoReconnect=true
   위 처럼 jdbc URL을 수정하면 된다.

3. JDBC 커넥션 설정 시 주기적으로 더미 SQL 조회 쿼리를 날린다. (validationQuery)
    WAS가 톰켓일 경우에는 DataSource 설정 시에 톰켓에서 제공하는 옵션을 이용하면 되겠다.
   /META-INF/context.xml 이나 %톰켓홈경로%conf/server.xml 에서 DataSource resource를 설정시..

<Resource name="jdbc/mysql_dbcp_pool"
    auth="Container"
    type="javax.sql.DataSource"
    driverClassName="com.mysql.jdbc.Driver"
    loginTimeout="100"
    maxActive="100"
    maxIdle="30"
    maxWait="50000"
    username="nonsan"
    password="nonsan12"
    validationQuery="SELECT 1"

이런 식으로 설정하면 되겠다. 옵션에 대한 자세한 문서는 하단 참조

validationQuery는 유효한 쿼리인데 유효 커넥션을 유지하기 위해 더미 SQL을 날리는 옵션이다. 더 자세한 내용은 꼭 하단 문서를 참조해야한다.
manual : http://commons.apache.org/proper/commons-dbcp/configuration.html


1. 의 경우에는 근본적인 해결은 아니라고 볼 수 있고

2. 의 경우에는 Transation 관련해서 버그가 있어서 제공벤더에서도 deprecated 된 상태이다. 만약 이 방법을 사용할려면 사용자 정의 트랜젝션 처리를 해야하는 것은 당연하다. 치명적인 데이터 일관성 문제가 생길수 도 있기 때문이다. (deprecated 된 것은 다 이유가 있다.)
참조 : http://dev.mysql.com/doc/refman/5.0/en/connector-j-reference-configuration-properties.html

3. 의 경우는 괜찮은 솔루션 이지만 commons-dbcp를 사용하지 않으면 다른 대안을 찾아야한다. 알아본 결과 타 DBCP 에서도 비슷한 옵션을 제공하고 있으니 꼭 메뉴얼 문서를 참조해보자. 단 대처가 없을 경우에는  2.를 사용하던지 아니면 사용하는 DBCP(DataSource)를 commons-dbcp로 수정해야 할 것이다.