在使用Spring jdbc连接数据库时遇到一个头疼的问题:程序启动以后,如果长时间不访问调用,当再次调用时会报错:
[quote]
[color=red]org.springframework.dao.DataAccessResourceFailureException: ConnectionCallback; SQL []; IO 错误: Software caused connection abort: recv failed; nested exception is java.sql.SQLRecoverableException: IO 错误: Software caused connection abort: recv failed[/color]
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:253)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:349)
at services.dao.DBUtil.subRptInfo(DBUtil.java:208)
at services.impl.ServiceImpl.subRptInfo(ServiceImpl.java:170)
at sun.reflect.GeneratedMethodAccessor65.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
[color=red]Caused by: java.sql.SQLRecoverableException: IO 错误: Software caused connection abort: recv failed[/color]
at oracle.jdbc.driver.T4CCallableStatement.executeForRows(T4CCallableStatement.java:1062)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1329)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3584)
at oracle.jdbc.driver.OraclePreparedStatement.execute(OraclePreparedStatement.java:3685)
at oracle.jdbc.driver.OracleCallableStatement.execute(OracleCallableStatement.java:4714)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.execute(OraclePreparedStatementWrapper.java:1376)
at org.apache.commons.dbcp.DelegatingCallableStatement.execute(DelegatingCallableStatement.java:221)
at services.dao.DBUtil$2.doInConnection(DBUtil.java:260)
at services.dao.DBUtil$2.doInConnection(DBUtil.java:1)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:342)
... 39 more
[color=red]Caused by: java.net.SocketException: Software caused connection abort: recv failed[/color]
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:147)
at oracle.net.ns.Packet.receive(Packet.java:300)
at oracle.net.ns.DataPacket.receive(DataPacket.java:106)
at oracle.net.ns.NetInputStream.getNextPacket(NetInputStream.java:315)
at oracle.net.ns.NetInputStream.read(NetInputStream.java:260)
at oracle.net.ns.NetInputStream.read(NetInputStream.java:185)
at oracle.net.ns.NetInputStream.read(NetInputStream.java:102)
at oracle.jdbc.driver.T4CSocketInputStreamWrapper.readNextPacket(T4CSocketInputStreamWrapper.java:124)
at oracle.jdbc.driver.T4CSocketInputStreamWrapper.read(T4CSocketInputStreamWrapper.java:80)
at oracle.jdbc.driver.T4CMAREngine.unmarshalUB1(T4CMAREngine.java:1137)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:290)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:192)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:531)
at oracle.jdbc.driver.T4CCallableStatement.doOall8(T4CCallableStatement.java:204)
at oracle.jdbc.driver.T4CCallableStatement.executeForRows(T4CCallableStatement.java:1041)
... 48 more
[/quote]
到处寻找资料后,发现是由于当数据库连接池中的连接被创建而长时间不使用的情况下,该连接会自动回收并失效,但客户端并不知道,在进行数据库操作时仍然使用的是无效的数据库连接造成的。解决方法是,在jdbc配置中加上:
select * from dual
这样客户端在使用一个无效的连接时会先对该连接进行测试,如果发现该连接已经无效,则重新从连接池获取有效数据库连接来使用。