Oracle连接没有关闭

时间:2012-01-20 06:51:27

标签: oracle connection-pooling odp.net

我们有使用odp.net连接到oracle数据库的ASP.NET应用程序。

最近我们开始遇到一些性能问题。似乎Oracle连接没有关闭并最终堆积,直到它崩溃我们的网站。

作为第一步,我们进行了代码审查,并确保在执行后关闭所有打开的连接。

OracleConnection cn = Helpers.ConnectToDB();
    try
    {

        cn.Open();
        //do somtehing
    }
    catch (Exception ex)
    {
        //log error
    }
    finally
    {
        cn.Close();
        cn.Dispose();
    }

但这并没有帮助,连接每隔几个小时就堆积起来并使我们的网站崩溃。

以下是昨天的连接日志:

TO_CHAR(DATE_TIME,'DD/MM/YYYY   MACHINE STATUS  CONNECTIONS 
19/01/2012 14:40:03 WORKGROUP\OTH-IIS-1 ACTIVE  1   
19/01/2012 14:38:00 WORKGROUP\OTH-IIS-1 ACTIVE  2   
19/01/2012 14:35:57 WORKGROUP\OTH-IIS-1 ACTIVE  2   
19/01/2012 14:34:55 WORKGROUP\OTH-IIS-1 ACTIVE  28  
19/01/2012 14:33:54 WORKGROUP\OTH-IIS-1 ACTIVE  26  
19/01/2012 14:31:51 WORKGROUP\OTH-IIS-1 ACTIVE  34  
19/01/2012 14:30:49 WORKGROUP\OTH-IIS-1 ACTIVE  96  
19/01/2012 14:29:47 WORKGROUP\OTH-IIS-1 ACTIVE  73  
19/01/2012 14:28:46 WORKGROUP\OTH-IIS-1 ACTIVE  119 
19/01/2012 14:27:44 WORKGROUP\OTH-IIS-1 ACTIVE  161 
19/01/2012 14:26:43 WORKGROUP\OTH-IIS-1 ACTIVE  152 
19/01/2012 14:25:41 WORKGROUP\OTH-IIS-1 ACTIVE  109 
19/01/2012 14:24:40 WORKGROUP\OTH-IIS-1 ACTIVE  74  
19/01/2012 14:23:38 WORKGROUP\OTH-IIS-1 ACTIVE  26  
19/01/2012 14:22:36 WORKGROUP\OTH-IIS-1 ACTIVE  2   
19/01/2012 14:21:35 WORKGROUP\OTH-IIS-1 ACTIVE  2

崩溃点发生在14:27:44,重新启动应用程序后,连接开始下降。

我们使用的连接字符串是:

<add name="OracleRead" connectionString="Data Source=xxx;User Id=yyy;Password=zzz;Max Pool Size=250;Connection Timeout=160;" providerName="Oracle.DataAccess"/>

那么这里有什么问题?

我们是否需要定义或更改其中一个属性:

Connection Lifetime, Decr Pool Size, Max Pool Size, Min Pool Size?

在这种情况下推荐的设置是什么?

5 个答案:

答案 0 :(得分:3)

您需要显式处置所有Oracle.DataAccess对象,包括Connections,Commands和Parameters。

请参阅此处评论中的代码示例:

https://nhibernate.jira.com/browse/NH-278

其他一些说明:

  • 首选使用关键字,因为即使在特殊情况下也能保证处理
  • ODP Paramter对象是特殊的(与常规ADO.NET参数契约相比),因为它也需要显式处理(例如,SQL Server版本不需要)

答案 1 :(得分:2)

我知道这个问题很老了,但我找到了一个似乎对我有用的解决方案。

我的解决方案是调用一个ASHX处理程序,然后返回一个图像,平均每个页面加载10-14次之间调用此服务。

我正在使用ODP.NET Oracle.DataAccess.Client命名空间V4.112.3.60作为64位。

我的所有代码都在使用语句(这里是混淆):

using (OracleConnection conn = new OracleConnection(System.Web.Configuration.WebConfigurationManager.ConnectionStrings["####"].ConnectionString))
{
    using (OracleCommand cmd = new OracleCommand(query, conn))
    {
        OracleParameter p = new OracleParameter("####", OracleDbType.Varchar2, 10);
        p.Direction = ParameterDirection.Input;
        p.Value = val;

        cmd.Parameters.Add(p);
        conn.Open();
        using(OracleDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection))
        {
            if (reader.HasRows)
            {
                while (reader.Read())
                {

                    OracleBlob lob = reader.GetOracleBlob(0);
                    //OracleLob lob = reader.GetOracleLob(0);
                    srcImage = new Bitmap(lob);
                }
                newImage = resizeImage(srcImage, new Size(120, 150));
                newImage.Save(context.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);
            }
            else
            {
                srcImage = new Bitmap("Images/none.jpg");
                newImage = resizeImage(srcImage, new Size(120, 150));
                newImage.Save(context.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);
                ProcessError(ref context, 500);
            }
        }
        p.Dispose();
    }
}

我尝试了很多东西:

  • 检查其他连接是否同时打开
  • 重写了一个SQL数据源控件,以便我可以更好地控制连接
  • 使用System.Data.OracleClient)

但是当谈到代码时,我发现有时候代码不会到达using块的末尾,下一个请求会在到达结束之前进入处理程序(我猜到的是处理最大请求到处理程序?)这导致一些会话在V $ SESSION中保持打开状态,我不得不手动关闭。

我遇到了这段代码:

OracleConnection.ClearAllPools();

尝试运行它,虽然会话将由处理程序保持打开,但至少这些会被此代码关闭,目前它在OracleConnection的使用块结束时运行(因此每次服务都是叫它清除池,希望处理程序设法执行那么远!)。

所以使用ClearAllPools方法似乎有效,但我知道它不是理想的解决方案。

答案 2 :(得分:1)

确保将所有连接包装在try / finally块中。仅为每个.Open()调用.Close()是不够的。您必须将.Close()调用放在finally块中。最简单的方法是使用using块创建连接。

答案 3 :(得分:1)

尝试在使用块中包含OracleConnection的使用(如果您使用的是C#):

using (OracleConnection conn = new OracleConnection(connectionString))
{
   ...
}

这样可以确保在使用完之后将其妥善处理掉。 OracleConnectionOracleDataReader(另一个示例)实现IDisposable,因此应在using语句中使用。

答案 4 :(得分:0)

一个简单的解决此问题的方法(在我的例子中)是通过指定Pooling = False来禁用连接池;在客户端连接字符串中。

显然,在高并发情况下(例如Web服务器),这不是一个好的解决方案,但是在我的情况下(每隔几秒钟执行一连串的批处理作业,每隔几秒钟执行一次新作业),不使用池化的开销可以忽略不计,并且比使Oracle中的100多个会话保持打开状态更好。

作为PS,我在代码的所有必需位置都使用了{}块,直到禁用池之前,仍然会看到此问题。