C#操作Oracle数据库连接超时的错误处理

 C#操作Oracle数据库连接超时的错误处理
 
 创建时间: 2007/08/09
 
 最近在使用C#操作Oracle数据库时发现了一个奇怪的问题, 在数据库会话存在超时限制时, 即使客户端重新连接数据库也无法继续数据库操作, 而且在连接时没有错误发生, 仅仅是 在连接后的操作中引发异常.
 
 程序本身很简单, 从一个消息中间件(MOM)中接收消息数据, 然后保存到数据库. 由于该应用是一个后台服务, 需要对错误处理比较小心, 因为与存在用户交互(界面)的程序相比,  后台服务需要更加健壮和更好的容错能力.
 
 因此在操作数据库时, 如果出现数据库连接问题而无法保存消息的情况, 应当不丢失消息并重新尝试连接数据库, 然后再次对消息进行处理.
 对于其它类型的错误, 例如主/外键问题, 数据类型问题等等因为消息数据本身错误引发的异常, 则应当保存到文件中, 并记录日志, 供人工审核, 然后对下面的消息数据进行进行处理.
 
 因此程序代码中对ORA-00028(session kill) ORA-02396(exceed idle time) ORA-01012(not logon)和 ORA-12535(timeout)等错误进行单独处理, 退出消息处理函数, 并在主函数中重新调用,  以重新连接数据库等资源.
 
  在服务主函数中:
  while (true)
            { try
                {
                    ProcessMessage(queueName);
                }
                catch (Exception e)
                {
                    LogManager.WriteLog(201, e.Message);
                    GC.Collect();
                }

                //Sleep
                if (mre.WaitOne(cf.TIME_OUT, false))
                    break;
  }
 
  而在消息处理函数中:
  private static void ProcessMessage(String queueName)
        {
            //Open database
            String strConn = cf.DB_CONN_STR;
            OracleConnection oc = new OracleConnection(strConn);
            oc.Open();
    
     //连接MOM....(略)
           
            do
            {
              //读取MOM消息数据...(略)
                    try
                    {
                        //保存MOM消息数据到数据库的操作...(略)
                       
                        str = msgInfo.MsgName + " save to database success.";
                        LogManager.WriteLog(301, str);
                    }
                    catch (OracleException e)
                    {
                        //In case of:   ORA-00028(session kill)
                        //              ORA-02396(exceed idle time)
                        //            ORA-01012(not logon)
                        //            ORA-12535(timeout)
                        if (e.Code == 2396 || e.Code == 1012 || e.Code == 28 || e.Code == 12535)
                        {
                            str = msgInfo.MsgName + " save to database fail, error code: " + e.Code.ToString() +", send message back and re-connect oracle.";
                            LogManager.WriteLog(301, str);

                            break; //quit loops
                        }
                        else //For other reason, just save data to dump file
                        {
                           //保存MOM消息数据到文件...(略)
                        }
                    }

                    catch (Exception e)
                    {
                        //保存MOM消息数据到文件...(略)
                    }
                }

             } while (true);

            oc.Close();
        }
       
        然而在测试中, 发现对ORA-00028(session kill)  ORA-01012(not logon)和 ORA-12535(timeout)均可成功的进行自动连接, 从而进行进行消息处理, 而对ORA-02396(exceed idle time) 的情况, 连接没有发现错误, 但是保存操作失败, 最终导致剩余的消息在数据库正常的情况下也无法进行处理了.
       
        对于存在资源限制的数据库, 均可出现上述问题, 因为后台服务一般是常连接.
        CREATE PROFILE developer_prof LIMIT
        IDLE_TIME 60
        CONNECT_TIME 480;
 
         ALTER SYSTEM SET RESOURCE_LIMIT=TRUE;
       
        在排除程序逻辑错误和数据库问题后, 唯一的疑点就是连接池, 也就是数据库重新连接时, 从客户端连接池中取出了一个现存的连接, 以提供效率, 但是正是这个连接已经 超时, 因此连接成功后, 操作还是引发了超时错误. 因此必须清除该连接池, 然后重新连接. 对.NET FRAMEWORK2.0版中OracleConnection新增了静态函数ClearPool和ClearAllPool.
        ClearPool方法在连接池中清除特定连接(通过参数指定)。如果在调用时该连接正在使用,则会对它们进行适当地标记,当该连接Close时,连接将被丢弃而不保存到连接池中。
 ClearAllPools则在连接池中清除所有连接。如果在调用该方法时连接正在使用,则会对连接进行适当地标记,当对连接调用 Close 时,连接将被丢弃而不保存到连接池。

        因此解决方法很简单, 在适当的地方添加连接池清除操作, 可以选择对所有异常出现的情况, 也可以针对连接超时等需要清空连接池的情况.例如:
       
        if (e.Code == 2396)
        {
            //Clear connection pool and close connection
            OracleConnection.ClearPool(oc);
           
            str = msgInfo.MsgName + " save to database fail, error code: " + e.Code.ToString() +", send message back and re-connect oracle.";
            LogManager.WriteLog(301, str);

            break; //quit loops
       }
         

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值