元旦节日后上班,客户打电话说系统无法登陆。登陆系统测试,发现首页能进入,输入用户名和密码,提交无法进入主页,查询后台发现执行验证用户和密码的sql语句时,提示“sqlException:数据库已关闭”。使用toad连接数据库,执行相应的sql语句一切正常。查看session状态发现大量inactive状态存在。自己无力下手,就大绝招,重新启动服务,问题就解决了。但是为什么会出现这个问题呢?于是就开始百度,看看有没有相同的问题存在,通过查阅资料,得出由于系统使用c3p0连接池连接数据库,连接池与数据库之间的连接已经中断,但是连接池的连接对象依然存在,因此系统在使用连接池连接数据库查询时,就会报“sqlExcetion:数据库已关闭”错误。
那么连接池与数据库之间为什么会断开呢?原因是:引用别人的话“程序如果长时间不进行数据库操作,那么数据源中的connection很可能已经断开。其原因有可能是防火墙或者连接数据库设置超时时间”。看到这里,心想也许真是这个问题,元旦三天假,系统无人使用,没有进行任何数据库操作。
进一步探索原因,首先查看数据库设置的最大空闲时间,系统使用的是oracle数据库,首先查看系统默认的空闲时间IDLE_TIME值,通过“select resource_name,resource_type,limit from dba_profiles where profile='DEFAULT'”,得到值为unlimited,然后查看sqlnet.ora文件,也没有配置SQLNET.EXPIRE_TIME值,那么可以肯定连接断开不是由oracle数据库连接空闲时间设置造成的,这也是与存在大量inactive状态连接不谋而合。那么断开原因的很可能与防火墙有关了。系统与数据库是部署在不同的服务器上,数据库和应用之间的访问通过防火墙,而防火墙对空闲的的连接配置的超时时间,一般默认为30分钟。关于防火墙具体的配置没有深入研究。
原因是发现了,如何避免以后再次出现这种问题呢?别人给出的解决方法是在配置c3p0时,一定要添加如下配置:
<!-- 每60秒检查所有连接池中的空闲连接。Default: 0 -->
<property name="idleConnectionTestPeriod" value="60" />
<!--如果设为true那么在取得连接的同时将校验连接的有效性。Default: false -->
<property name="testConnectionOnCheckin" value="true" />
<!--c3p0将建一张名为Test的空表,并使用其自带的查询语句进行测试。如果定义了这个参数那么 属性preferredTestQuery将被忽略。你不能在这张Test表上进行任何操作,它将只供c3p0测试
使用。Default: null -->
<property name="automaticTestTable" value="Test" />
这样就不会出现连接超时的问题了。好了,收工。