3

这是我的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()

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

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

4

4 回答 4

6

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

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

简短的回答(对于 c#):

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

“使用”确保 .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);
  }
}

有什么真正的区别吗?否 - 非托管资源是由 .Close 处理的连接。如果您在 finally 块中检查连接状态并调用 .Close 如果它仍然打开,您将看不到任何功能差异(除了延迟跟踪)。

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

也就是说,对于一次性对象的推荐模式是使用“使用”块。是的,我想您确实可以选择使用 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();
于 2016-03-01T14:56:06.233 回答
5

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

如果连接尚未关闭,Dispose 会关闭连接,并且还会将其处理掉,这样您就无法再次重新打开它。

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

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

于 2016-02-29T15:45:28.693 回答
2

实现资源的更标准实现IDisposable是通过以下方式包装它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 文档中使用的示例Oracle.DataAccess也鼓励使用Dispose

于 2016-02-29T15:57:46.350 回答
1

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

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

编辑:

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

于 2016-02-29T15:54:51.937 回答