首先,这不是一篇技术文章,而是小弟在实际中的一个问题,请大家帮忙解决一下,谢谢。写一个方法,在出现异常时递归……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.   

    1:如果不执行finally的话,证明一直在调用 catch 里的return this.selectMax();不断递归,造成了死循环.
    2:并发线程,对共享变量,要lock.
    3:在catch块也加上.if(this.SqlCon!=null)
                 { this.SqlCon.Close(); }
      

  3.   

    引用楼上的
    1:如果不执行finally的话,证明一直在调用 catch 里的return this.selectMax();不断递归,造成了死循环.  很有可能是这样这样子的递归调用是很危险的
      

  4.   

    你写的程序有问题
    this.SSS();就是又重新执行程序
      

  5.   

    递归要注意结束条件,还有,finally不执行是不可能的,因为在执行它之前先进了cacth块,又调用了本方法,这样finally
    就挂起了,一直要等到这个递归遇到结束条件时它才会逐一返回,这时才会逐一的来执行前面挂起的finally块中的语句;