最近的项目是开发一个异构的数据库同步系统,其中有个需求是要在服务器故障时程序不能崩溃,服务器恢复正常后,程序也能自动正常运行。而经过长时间的测试,发现服务器关闭状态下,程序日志是会记录异常,不会崩溃,但是关闭服务器时间越久,程序恢复正常的时间越长,一直想不通,而在程序完成关闭重新打开就能马上恢复正常,程序里的任务重启并不能解决问题。因为是高频率的访问数据库,所以程序里用了大量的静态方法,刚开始以为是因为静态方法导致资源没有释放造成的,但是程序里的每个连接我都有进行释放资源,不该出现这种情况。而程序重启能马上恢复正常,是因为程序关闭后释放了内存里使用的资源,改用对象方式也没能解决问题,最后发现问题是出现在数据库连接池上,ado.net默认是使用数据库连接池方式工作的,是否使用数据库连接池在连接字符串中设置。如下代码并没有真正释放连接,而是将连接放回连接池:
public static void closeAll(OracleConnection con, OracleCommand com)
{
if (com != null)
{
com.Dispose();
}
if (con != null)
{
con.Close();
}
}
当服务器异常时,程序日志显示出相应的异常,但当服务器恢复后,程序却不能恢复,服务器挂越久,程序恢复时间越长,元凶就是数据库连接池,如下代码:
OracleConnection orclConCatchException = null;
OracleCommand commandCatchException = null;
try
{
orclConCatchException = new OracleConnection(sConsql);
orclConCatchException.Open();
commandCatchException = orclConCatchException.CreateCommand();
}
catch (Exception e)
{
form.SetText(DateTime.Now.ToString() + subTaskName + "反向---失败:" + e.Message.ToString());
OracleServerAccess.closeAll(orclConCatchException, commandCatchException);
return;
}
因为程序里要new一个连接是先到数据库连接池进行匹配,如果当前的连接字符串与数据库连接池里的属性一样,就直接拿来用,所以是不报错的,也恢复不了,因为每次都是拿到连接池里的,当程序new一个连接,如果连接池里没有空闲的连接,就真正实际上new一个。所以只要在发生异常的时候清空连接池OracleConnection.ClearAllPools();即可,orclConCatchException = new OracleConnection(sConsql)所取得的对象如果是从数据库连接池获得的,而此时数据库就算是关闭的也不会报错,如果是实际new一个的话就会报错。
新手第一次写,如果有错误之处请帮忙纠正。