首先,这不是一篇技术文章,而是小弟在实际中的一个问题,请大家帮忙解决一下,谢谢。写一个方法,在出现异常时递归……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分钟在将它重新启动,不知道这样好不好?大家有什么看法?
现在真的没有办法了,写的这么多,就是想把情况写的具体点,请高手们看的明白,帮小弟解决一下,看的累的不要骂,请见谅!

解决方案 »

  1.   

    直接try
    {
    }
    catch(...)
    {}catch中捕获所有的异常,当当前网络连接不通的时候,就关闭close连接等,然后等待一段时间,再重连数据库好了...
      

  2.   

    哇,没见过这样的,应该来说,不管如何 finally 中的语句都会执行啊!
      

  3.   

    不是不会执行,你的程序看起来陷于无限递归中,怎么会到执行finally?
      

  4.   

          我的看法是下面的,不知道对不对。
     第一段里,只要执行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块问题的。 我没环境调试啊,如果有错请指教。
      

  5.   


    不是说return的同时都会先执行finally吗?这和递归有什么关系?
      

  6.   

    有返回值的,finally都会执行,
      

  7.   

    谢谢上面兄弟~~们的回复但是 songeastchang, finally 中是不允许rerurn存在的…… 
      

  8.   

    finally应该是在退出方法的同时执行的,在你这段代码中,不断的递归sss()方法,它一直都退不出,所以你永远也看不到它输出however finally must be executed?
      

  9.   

    递归的程序,相当于try catch没有结束,你的代码一直在嵌套的ssss方法的catch块里执行,根本就没有运行到finally,finally是在离开catch模块后执行,而且是一定执行,你都没离开catch块,执行什么?
    还这么大惊小怪的。
      

  10.   

    try catch finnaly 是一个整体,Catch也没有过怎么能过Finnaly呢?
    也就是说有了Try开始到Finnaly是必须过的,没有错呀