Search code examples
c#powershellpowershell-3.0odp.netoracle-manageddataaccess

How to properly close ODP.net connection : dispose() or close()?


this is my powershell code :

[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()

So I'm opening ODP.NET connection with $OracleConnexion.open() then closing it with $OracleConnexion.close() is it sufficient to close properly my connection to Oracle Database? Or should I use $OracleConnexion.Dispose() ?

I execute my powershell every 5min via Task scheduler... So maybe Should I use Dispose() to avoid memory saturation?


Solution

  • It looks like everybody else, I noticed late that you're in powershell. In that case, it doesn't really matter. Everything is going to get cleaned up when the shell ends regardless. I suppose you could add a [catch] and maybe close/dispose the connection there if it's still open, but I think that would only be necessary if you planned on letting your script continue.

    I'll leave my longwinded c# answer below. Even though it doesn't really apply to your script, it explains the difference (or lack thereof).

    The short answer (for c#):

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

    "using" ensures that .Dispose is called at the end of the block even if an exception is thrown. That way you never risk a connection being orphaned until garbage collection finally gets around to cleaning it up and that might be well after you run out of database connections.

    The long answer:

    Using a reflector, you will see that Dispose calls 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);
      }
    }
    

    Is there any real difference? No - the unmanaged resource IS the connection which is taken care of with .Close. You'd see no functional difference (other than delayed tracing) if you checked the connection status in a finally block and called .Close there if it was still open.

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

    That said the recommended pattern for idisposible objects is to use a "using" block. Yes I suppose it is true that you have the option to reopen the connection with close, but I don't see that being a useful thing to do.

    If you didn't use a using or a finally and an exception is thrown and close/dispose is never called, then freeing the connection to the db would be nondeterministic - Dispose(false) would happen whenever the garbage collector got around to it - and that might be long after you run out of connections to your db.

        OracleConnection conn = null;
        conn = new OracleConnection(connectionString);
        conn.Open();
    
        //exception occurs - Close is never called - resource leak!!
    
        conn.Close();