我们有使用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?
在这种情况下推荐的设置是什么?
答案 0 :(得分:3)
您需要显式处置所有Oracle.DataAccess对象,包括Connections,Commands和Parameters。
请参阅此处评论中的代码示例:
https://nhibernate.jira.com/browse/NH-278
其他一些说明:
答案 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();
}
}
我尝试了很多东西:
但是当谈到代码时,我发现有时候代码不会到达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))
{
...
}
这样可以确保在使用完之后将其妥善处理掉。 OracleConnection
和OracleDataReader
(另一个示例)实现IDisposable
,因此应在using
语句中使用。
答案 4 :(得分:0)
一个简单的解决此问题的方法(在我的例子中)是通过指定Pooling = False来禁用连接池;在客户端连接字符串中。
显然,在高并发情况下(例如Web服务器),这不是一个好的解决方案,但是在我的情况下(每隔几秒钟执行一连串的批处理作业,每隔几秒钟执行一次新作业),不使用池化的开销可以忽略不计,并且比使Oracle中的100多个会话保持打开状态更好。
作为PS,我在代码的所有必需位置都使用了{}块,直到禁用池之前,仍然会看到此问题。