如何正确关闭ODP.net连接:dispose()或close()?

时间:2016-02-29 15:40:43

标签: c# powershell powershell-v3.0 odp.net oracle-manageddataaccess

这是我的powershell代码:

[void][System.Reflection.Assembly]::LoadFile("C:\DLL\Oracle.ManagedDataAccess.dll")
$OracleConnexion = New-Object Oracle.ManagedDataAccess.Client.OracleConnection('User Id=test;Password="test";Data Source=10.2.2.1/TEST')
$TimeOut = 60

$OracleConnexion.Open()

$Query=$OracleConnexion.CreateCommand()
$Query.CommandText="Select * FROM TEST"
$Query.CommandTimeout = $Timeout

$ExecuteRequete=$Requete.ExecuteReader()

while ($ExecuteRequete.Read()) {

    $SiebelLastRecord += $ExecuteRequete.GetDateTime(0).ToString()

} 

$OracleConnexion.Close()

所以我打开与$OracleConnexion.open()的ODP.NET连接然后用$OracleConnexion.close()关闭它是否足以正确关闭我与Oracle数据库的连接?或者我应该使用$OracleConnexion.Dispose()

我通过任务调度程序每5分钟执行一次PowerShell ...所以也许我应该使用Dispose()来避免内存饱和?

4 个答案:

答案 0 :(得分:5)

关闭关闭连接并允许您再次重新打开它。

Dispose关闭连接,如果它尚未关闭并且也将其处理掉,因此您无法再次重新打开它。

使用dispose - dispose释放资源的内存, 如果该资源是开放的,那么表现良好的.dispose方法将关闭该资源。

  

使用ConnectionPooling Dispose()与Close():   https://community.oracle.com/thread/165664?start=0&tstart=0

答案 1 :(得分:5)

看起来像其他人一样,我很晚才注意到你在使用PowerShell。在这种情况下,它并不重要。无论如何,当shell结束时,一切都会被清理干净。我想你可以添加[catch]并关闭/处理那里的连接,如果它仍处于打开状态,但我认为只有你计划让脚本继续运行才有必要。

我将在下面留下我的longwinded c#答案。虽然它并不真正适用于您的脚本,但它解释了差异(或缺乏)。

简答(对于c#):

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

“using”确保即使抛出异常也会在块的末尾调用.Dispose。这样,在垃圾收集最终完成清理并且在用完数据库连接后可能会很好的情况下,您永远不会冒连接孤立的风险。

答案很长:

使用反射器,您将看到Dispose调用Close:

protected override void Dispose(bool disposing)
{
  if (ProviderConfig.m_bTraceLevelPublic)
    Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry);
  this.m_disposed = true;
  this.m_dataSource = string.Empty;
  this.m_serverVersion = string.Empty;
  try
  {
    bool flag = this.m_connectionState == ConnectionState.Closed && this.m_oracleConnectionImpl == null;
    try
    {
      if (!disposing)
      {
        if (!flag)
        {
          if (OraclePool.m_bPerfNumberOfReclaimedConnections)
            OraclePool.PerformanceCounterIncrement(OraclePerfParams.CounterIndex.NumberOfReclaimedConnections, this.m_oracleConnectionImpl, this.m_oracleConnectionImpl.m_cp);
        }
      }
    }
    catch (Exception ex)
    {
      if (ProviderConfig.m_bTraceLevelPublic)
        Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Error, ex.ToString());
    }
    if (!flag)
    {
      try
      {
        this.Close();
      }
      catch (Exception ex)
      {
        if (ProviderConfig.m_bTraceLevelPublic)
          Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Error, ex.ToString());
      }
    }
    try
    {
      base.Dispose(disposing);
    }
    catch (Exception ex)
    {
      if (ProviderConfig.m_bTraceLevelPublic)
        Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Error, ex.ToString());
    }
    try
    {
      GC.SuppressFinalize((object) this);
    }
    catch (Exception ex)
    {
      if (!ProviderConfig.m_bTraceLevelPublic)
        return;
      Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Error, ex.ToString());
    }
  }
  catch (Exception ex)
  {
    if (!ProviderConfig.m_bTraceLevelPublic)
      return;
    Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Error, ex.ToString());
  }
  finally
  {
    if (ProviderConfig.m_bTraceLevelPublic)
      Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit);
  }
}

有什么真正的区别吗?否 - 非托管资源是与之关联的连接。关闭。如果你在finally块中检查了连接状态并且在那里调用了.Close,那么你看不到任何功能差异(延迟跟踪除外)。

  OracleConnection conn = null;
  try
  {
    conn = new OracleConnection(connectionString);
  }
  finally
  {
    if(conn.State != ConnectionState.Closed)
      conn.Close();
  }

那就是说idisposible对象的推荐模式是使用“using”块。是的,我认为您可以选择以close方式重新打开连接,但我认为这不是一件有用的事情。

如果你没有使用using或者finally并抛出异常并且从不调用close / dispose,那么释放与db的连接将是不确定的 - 每当垃圾收集器到处时就会发生Dispose(false)对它 - 这可能是你的数据库连接用完后很长一段时间。

    OracleConnection conn = null;
    conn = new OracleConnection(connectionString);
    conn.Open();

    //exception occurs - Close is never called - resource leak!!

    conn.Close();

答案 2 :(得分:1)

我会用using语句包装你的连接。完成连接后,请在添加支架之前将其关闭。为了100%安全,我会做这样的事情:

using(OracleConnexion Con = new OracleConnection (...))
{
    Con.Open()
    ...
    Con.Close()
}

修改

我添加了Con.Close(),因为在过去,dispose未在ODP.NET中正确实现。连接保持打开状态。我们必须强制手动关闭连接,这就是为什么在示例中,我指定了Close

答案 3 :(得分:1)

实施using的资源的更多标准实施是将其using (OracleConnection connection = new OracleConnection(connectionString)){ using (OracleCommand command = new OracleCommand(sql, connection)) using (OracleDataReader reader = cmd.ExecuteReader()) { } connection.Close(); //optional } 包裹起来:

.Dispose

这相当于在执行块之后实现Dispose。在内部,.Close()也将处理结束。不过,您也可以在命令块之后调用Oracle.DataAccess

使用Dispose的oracle文档中的sample也鼓励使用i = 1 while(i<=m){ Date = London.Events$start_time[i] j=1 while(j<=n){ Hotel = London.Hotels$AS400.ID[j] Day.Zero[i,j] = sum(London.Bookings$No.of.Rooms[London.Bookings$Stay.Date == Date & London.Bookings$Legacy.Hotel.Code == Hotel]) j=j+1 } i=i+1 }