首先,这不是一篇技术文章,而是小弟在实际中的一个问题,请大家帮忙解决一下,谢谢。写一个方法,在出现异常时递归……public void sss() {
int s = 9;
try
{
if (s % 2 == 0)
{
Console.WriteLine("In order");
}
else
{
throw new Exception("Number Exception");
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
this.sss();
}
finally {
Console.WriteLine("however finally must be executed?");
}
}在出现异常的时候执行catch块,然后重新执行sss(),根本不执行finally块。不是说finally块无论什么情况下都会被执行吗???我写的是一个用来监测局域网上所有IP地址的windows service,由于IP非常多,大约1000+,每个网段并发一个线程。在线程并发之前,需要从数据库中读取一些数据,付值给程序的一些变量,然后才能正常操作。线程操作时,每过一段时间,也要大量读数据库的数据和写数据库操作。但是在我们这里,经常性的会发生一些网络问题:网络拥挤,每天15点到17点时经常发生,但不是每天都有。每次发生大约10几20分钟,在这种时候,打个比方说,如果你每秒ping 10次数据库,有5次能通,5次不通。过后一切正常。原因不明(呵呵不好意思)。所以我的想法是,如果正好在这个时期要进行数据库的操作,而且这个操作必须要成功的写入数据或者读取数据,用以下的方法:public string selectMax() {
string sql = "select ProcesTime, LoopTimesAnHour from LanApp_Ipaddress where RecordId = (select max(RecordId) from LanApp_Ipaddress)"; /**这个方法写在一个数据库操作的类中,
*this.SqlCon是一个SqlConnection, this.SqlDa是DataReader
*this.SqlCmd是SqlCommand
*首先通过this.ConnectionOperation(sql)方法
*new一个SqlConnection,将它付值个本类中的SqlCon
*我给每一个SQL操作一个新的连接,然后再将它释放
*然后this.SqlCmd使用这个连接,使用sql作为操作字符串
**/ this.ConnectionOperation(sql);
try
{
if (this.SqlCon != null) //如果连接失败,就返回null
{
this.SqlDa = this.SqlCmd.ExecuteReader();
}
else
{
throw this.SqlEx; //这是定义的一个SQL连接失败的异常
} string back = "";
if (this.SqlDa.Read())
{
back = Convert.ToDateTime(this.SqlDa[0]).ToString("yyyy-MM-dd HH:mm:ss");
Program.LOOP = Convert.ToInt32(this.SqlDa[1]);
}
this.SqlDa.Close(); //每次使用完都有正常关闭 if (Program.ISEXCEPTION)
{
Program.ISEXCEPTION = false; //由于是并发线程,设置一个静态变量表示出现异常
}
return back;
}
catch (Exception e)
{
if (!Program.ISEXCEPTION)
{
Program.ISEXCEPTION = true;
} Thread.Sleep(1000);
return this.selectMax();
}
finally {
//如果出现异常,直接执行return this.selectMax(),finally不会被执行 if (this.SqlCon.State != ConnectionState.Closed)
this.SqlCon.Close();
}
}正常的情况下,这段代码运行没有问题,就算是将网线拔掉,连接不到数据库,也不会出现异常,它会一直进行连接。我的每一个SQL操作都是这种模式下来的,开始的时候给每个SQL操作new一个新的连接,结束后Close()掉,让它返回连接池,释放资源。这样的话一个DataReader在运作的时候也同时只配合一个Connection,只要用完后也及时关闭。
但是……但是,异常还是出现了,只是在上面提到的那个特殊的时刻,15点16点网络出现拥挤的时候,还是出现异常。刚开始的时候出现数据库连接的失败,然后自动又连上,进行一些的操作,然后又连不上,然后再连上,再操作,然后再断掉,再连……,其实这就是我想要的效果,只要过了这10几20分钟,网络恢复正常,程序也自然恢复正常。但是好景不长,没过多长时间,就出现异常,程序终止。看看上面的代码,想了想,唯一能出现异常的地方,应该就是finally中的this.SqlCon.Close了吧。果不其然,其实就是它,这句没有做异常处理。看看异常信息,说是SqlCon没有引用任何值(英文的信息,大约就是这个意思,中文的具体翻译我不知道,我想大家也都明白吧)。我就纳闷了,即使SqlConnection是null,执行个Close()也不会出现异常啊???因为这个异常只是特定的时刻才能发生(每天一次,或者没有),又因为这是个Service,调试起来比较困难,所以一直都不能知道具体的原因。昨天我又将这个Service转化成一个控制台应用程序,为了就是能方便调试,然后就是发现这个问题,如果异常出现,直接执行catch块中的递归函数,finally中的代码根本不执行,如果没有出现异常,finally正常执行。我想了想,有没有可能是因为:异常出现后,finally块中的代码没有执行,所以连接没有被释放,有迅速的进行一次新的连接,因为网络问题频繁的出现,又因为是并发的多线程,所以很快的将连接池添满,造成溢出,然后出现异常?
这个也是我瞎猜的,因为我真的是找不到根源了。如果这个异常不能排除的话,我想,是不是在程序的最外层加上一套try...catch,当出现这个特殊异常的时候,抛到最外面,然后catch调用一个外部程序,先将这个Service停止,过个10分钟在将它重新启动,不知道这样好不好?大家有什么看法?
现在真的没有办法了,写的这么多,就是想把情况写的具体点,请高手们看的明白,帮小弟解决一下,看的累的不要骂,请见谅!
int s = 9;
try
{
if (s % 2 == 0)
{
Console.WriteLine("In order");
}
else
{
throw new Exception("Number Exception");
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
this.sss();
}
finally {
Console.WriteLine("however finally must be executed?");
}
}在出现异常的时候执行catch块,然后重新执行sss(),根本不执行finally块。不是说finally块无论什么情况下都会被执行吗???我写的是一个用来监测局域网上所有IP地址的windows service,由于IP非常多,大约1000+,每个网段并发一个线程。在线程并发之前,需要从数据库中读取一些数据,付值给程序的一些变量,然后才能正常操作。线程操作时,每过一段时间,也要大量读数据库的数据和写数据库操作。但是在我们这里,经常性的会发生一些网络问题:网络拥挤,每天15点到17点时经常发生,但不是每天都有。每次发生大约10几20分钟,在这种时候,打个比方说,如果你每秒ping 10次数据库,有5次能通,5次不通。过后一切正常。原因不明(呵呵不好意思)。所以我的想法是,如果正好在这个时期要进行数据库的操作,而且这个操作必须要成功的写入数据或者读取数据,用以下的方法:public string selectMax() {
string sql = "select ProcesTime, LoopTimesAnHour from LanApp_Ipaddress where RecordId = (select max(RecordId) from LanApp_Ipaddress)"; /**这个方法写在一个数据库操作的类中,
*this.SqlCon是一个SqlConnection, this.SqlDa是DataReader
*this.SqlCmd是SqlCommand
*首先通过this.ConnectionOperation(sql)方法
*new一个SqlConnection,将它付值个本类中的SqlCon
*我给每一个SQL操作一个新的连接,然后再将它释放
*然后this.SqlCmd使用这个连接,使用sql作为操作字符串
**/ this.ConnectionOperation(sql);
try
{
if (this.SqlCon != null) //如果连接失败,就返回null
{
this.SqlDa = this.SqlCmd.ExecuteReader();
}
else
{
throw this.SqlEx; //这是定义的一个SQL连接失败的异常
} string back = "";
if (this.SqlDa.Read())
{
back = Convert.ToDateTime(this.SqlDa[0]).ToString("yyyy-MM-dd HH:mm:ss");
Program.LOOP = Convert.ToInt32(this.SqlDa[1]);
}
this.SqlDa.Close(); //每次使用完都有正常关闭 if (Program.ISEXCEPTION)
{
Program.ISEXCEPTION = false; //由于是并发线程,设置一个静态变量表示出现异常
}
return back;
}
catch (Exception e)
{
if (!Program.ISEXCEPTION)
{
Program.ISEXCEPTION = true;
} Thread.Sleep(1000);
return this.selectMax();
}
finally {
//如果出现异常,直接执行return this.selectMax(),finally不会被执行 if (this.SqlCon.State != ConnectionState.Closed)
this.SqlCon.Close();
}
}正常的情况下,这段代码运行没有问题,就算是将网线拔掉,连接不到数据库,也不会出现异常,它会一直进行连接。我的每一个SQL操作都是这种模式下来的,开始的时候给每个SQL操作new一个新的连接,结束后Close()掉,让它返回连接池,释放资源。这样的话一个DataReader在运作的时候也同时只配合一个Connection,只要用完后也及时关闭。
但是……但是,异常还是出现了,只是在上面提到的那个特殊的时刻,15点16点网络出现拥挤的时候,还是出现异常。刚开始的时候出现数据库连接的失败,然后自动又连上,进行一些的操作,然后又连不上,然后再连上,再操作,然后再断掉,再连……,其实这就是我想要的效果,只要过了这10几20分钟,网络恢复正常,程序也自然恢复正常。但是好景不长,没过多长时间,就出现异常,程序终止。看看上面的代码,想了想,唯一能出现异常的地方,应该就是finally中的this.SqlCon.Close了吧。果不其然,其实就是它,这句没有做异常处理。看看异常信息,说是SqlCon没有引用任何值(英文的信息,大约就是这个意思,中文的具体翻译我不知道,我想大家也都明白吧)。我就纳闷了,即使SqlConnection是null,执行个Close()也不会出现异常啊???因为这个异常只是特定的时刻才能发生(每天一次,或者没有),又因为这是个Service,调试起来比较困难,所以一直都不能知道具体的原因。昨天我又将这个Service转化成一个控制台应用程序,为了就是能方便调试,然后就是发现这个问题,如果异常出现,直接执行catch块中的递归函数,finally中的代码根本不执行,如果没有出现异常,finally正常执行。我想了想,有没有可能是因为:异常出现后,finally块中的代码没有执行,所以连接没有被释放,有迅速的进行一次新的连接,因为网络问题频繁的出现,又因为是并发的多线程,所以很快的将连接池添满,造成溢出,然后出现异常?
这个也是我瞎猜的,因为我真的是找不到根源了。如果这个异常不能排除的话,我想,是不是在程序的最外层加上一套try...catch,当出现这个特殊异常的时候,抛到最外面,然后catch调用一个外部程序,先将这个Service停止,过个10分钟在将它重新启动,不知道这样好不好?大家有什么看法?
现在真的没有办法了,写的这么多,就是想把情况写的具体点,请高手们看的明白,帮小弟解决一下,看的累的不要骂,请见谅!
{
}
catch(...)
{}catch中捕获所有的异常,当当前网络连接不通的时候,就关闭close连接等,然后等待一段时间,再重连数据库好了...
第一段里,只要执行catch块里就产生了递归了,如果2级递归正常结束,我估计还是执行第一层的finally块的
catch (Exception e)
{
Console.WriteLine(e.ToString());
this.sss();
} 下面那段数据库操作的代码里,出现异常执行到catch块时,return 跳出整个方法了,必然不会执行finally块
可以把那个临时变量string back 提示为整个selectMax方法下的一个临时变量,在最后finnaly块 return back;
public string selectMax() {
string sql = "select ProcesTime, LoopTimesAnHour from LanApp_Ipaddress where RecordId = (select max(RecordId) from LanApp_Ipaddress)"; /**这个方法写在一个数据库操作的类中,
*this.SqlCon是一个SqlConnection, this.SqlDa是DataReader
*this.SqlCmd是SqlCommand
*首先通过this.ConnectionOperation(sql)方法
*new一个SqlConnection,将它付值个本类中的SqlCon
*我给每一个SQL操作一个新的连接,然后再将它释放
*然后this.SqlCmd使用这个连接,使用sql作为操作字符串
**/ string back = ""; //提升到这里来 111111111111111 this.ConnectionOperation(sql);
try
{
if (this.SqlCon != null) //如果连接失败,就返回null
{
this.SqlDa = this.SqlCmd.ExecuteReader();
}
else
{
throw this.SqlEx; //这是定义的一个SQL连接失败的异常
} if (this.SqlDa.Read())
{
back = Convert.ToDateTime(this.SqlDa[0]).ToString("yyyy-MM-dd HH:mm:ss");
Program.LOOP = Convert.ToInt32(this.SqlDa[1]);
}
this.SqlDa.Close(); //每次使用完都有正常关闭 if (Program.ISEXCEPTION)
{
Program.ISEXCEPTION = false; //由于是并发线程,设置一个静态变量表示出现异常
}
}
catch (Exception e)
{
if (!Program.ISEXCEPTION)
{
Program.ISEXCEPTION = true;
} Thread.Sleep(1000);
return this.selectMax();
}
finally {
//如果出现异常,直接执行return this.selectMax(),finally不会被执行 if (this.SqlCon.State != ConnectionState.Closed)
this.SqlCon.Close();
return back; //换到这里来返回整个方法的结果 222222222 }
} 试试这个方法对不,只是针对不执行finally块问题的。 我没环境调试啊,如果有错请指教。
不是说return的同时都会先执行finally吗?这和递归有什么关系?
还这么大惊小怪的。
也就是说有了Try开始到Finnaly是必须过的,没有错呀