본문 바로가기
trouble shooting

종종 발생되는 Already closed 에러

by chunkind 2023. 2. 27.
반응형

상황

아래와 같은 예외가 가끔 떨어지고 다시 접속하면 잘 된다.

java.sql.SQLException: Already closed.
at org.apache.commons.dbcp.PoolableConnection.close(PoolableConnection.java:114)
at org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.close(PoolingDataSource.java:191)
at org.springframework.jdbc.datasource.DataSourceUtils.doCloseConnection(DataSourceUtils.java:343)
at org.springframework.jdbc.datasource.DataSourceUtils.doReleaseConnection(DataSourceUtils.java:330)
at org.springframework.jdbc.datasource.DataSourceUtils.releaseConnection(DataSourceUtils.java:296)
at org.mybatis.spring.transaction.SpringManagedTransaction.close(SpringManagedTransaction.java:129)
at org.apache.ibatis.executor.BaseExecutor.close(BaseExecutor.java:90)
at org.apache.ibatis.executor.CachingExecutor.close(CachingExecutor.java:64)
at org.apache.ibatis.session.defaults.DefaultSqlSession.close(DefaultSqlSession.java:263)
at org.mybatis.spring.SqlSessionUtils.closeSqlSession(SqlSessionUtils.java:195)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:445)
at cohttp://m.sun.proxy.$Proxy7.insert(Unknown Source)
at org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate.java:279)
..... 생략....

원인

Tomcat이 DB pool에서 MySQL connection을 물고 있더라도 MySQL 입장에서는 오래된 connection을 문제라고 생각하고 끊어버린다. 오랜만에 애플리케이션에 접속하여 끊어진 connection을 사용할 경우 발생한다.
즉 tomcat이 사용하는 DB pool인 DBCP가 MySQL에 의해 끊어진 connection을 주고 애플리케이션이 이걸 사용하려다가 발생하는 에러이다.

해결책

DBCP가 connection을 돌려주기 전 해당 connection이 살아있는지 검사하는 설정을 해야 한다.
server.xml 또는 context.xml에서 DataSource를 아래처럼 수정해주면 된다.
<Resource name="jdbc/MyDS" auth="Container" type="javax.sql.DataSource"
    username="nextree"
    password="xxx"
    driverClassName="com.mysql.jdbc.Driver"
    url="jdbc:mysql://localhost:3306/test"
    validationQuery="select 1" />
 
validationQuery 설정은 DBCP가 connection을 반환하기전 설정된 쿼리를 날려 connection이 유효한지 검사하고 유효하지 않다면 다시 연결하여 유효한 connection을 반환한다.
반응형