views:

226

answers:

2

According to the MSDN documentation for the OracleClient.OracleCommand:

Public Sub ReadMyData(ByVal connectionString As String)
    Dim queryString As String = "SELECT EmpNo, DeptNo FROM Scott.Emp"
    Using connection As New OracleConnection(connectionString)
        Dim command As New OracleCommand(queryString, connection)
        connection.Open()
        Dim reader As OracleDataReader = command.ExecuteReader()
        Try
            While reader.Read()
                Console.WriteLine(reader.GetInt32(0) & ", " _
                   & reader.GetInt32(1))
            End While
        Finally
            ' always call Close when done reading.
            reader.Close()
        End Try
    End Using
End Sub

The OracleCommand is not wrapped in a Using block.

Question: Should it be? OracleCommand inherits from DbCommand, which implements IDisposable.

I'm looking at code that does the following, and we're having problems with implicit cursors not getting closed:

     Dim cmd As OracleCommand = createCommand("some sql")
     ds = GetDataSet(cmd)
     cmd.Dispose()
     cmd = Nothing

GetDataSet looks like:

  Dim da As New OracleDataAdapter()
  Dim ds As New DataSet()

  Using conn As OracleConnection = GetOpenConnection()
     cmd.Connection = conn
     da.SelectCommand = cmd
     da.Fill(ds, 0)
     cmd.Connection = Nothing
  End Using
  da.Dispose()
  da = Nothing
  Return ds

Is this going to leak resources?

+1  A: 

First off, I think you should explicitly close your connections in your code, because depending on the provider there is some additional work that gets done when you call the Close method

Conrad
But according to the MSDN code, this isn't needed. And if I have a Using cmd = new OracleCommand() block, then do I need to explicitly close it?
chris
Disposing of a command does not mean that the associated connection is closed. Remember that a connection can be used by several commands.
Conrad
A: 

How are you determining that the implicit cursors are open and that that is a problem? The reason I ask is that calling the "Close" method does not actually close the connection. It just lets the pool know that it is no longer being used and can be reallocated somewhere else. This is done for performance reasons because actually physically opening a connection is expensive. The same connection will be reused many times and may well remain open even after calling "Close" so if you are using some Oracle tools to peer into the connections it may be leading you astray.

I have never seen any reason to explicitly dispose of the command object. It is just a collection of parameters and other info.

If you use a using block as you have, there is absolutely no need to call "Close" or "Dispose" explicitly in code. That is the whole point of the using block. It protects you from forgetting to call Close since that is exactly what it does for you.

DancesWithBamboo
select a.value, s.username, s.sid, s.status, s.schemaname, s.machine, s.logon_time, s.state, s.serial#from v$sesstat a, v$statname b, v$session swhere a.statistic# = b.statistic# and s.sid=a.sid and b.name = 'opened cursors current' and s.type='USER'order by s.username;We have max. cursors set to 300, but we keep getting ORA-01000 error. Monitoring show that 100 cursors are getting opened each request (it's a summary page, queries lots of tables) but they're never closed, so my assumption is that we're not closing or disposing of something.
chris
Are you calling GetDataSet in a tight loop? Releasing the connection to the pool is an asynchronous operation and if you are in a tight loop it will probably grab a new connection for each iteration because it isn't releasing them fast enough. Wow, that seems like a lot of connections for one page. Might be a design issue there.
DancesWithBamboo
Definitely a design issue, but it surfaced the problem. Solution was to wrap each new OracleCommand in a using, and each DataReader in a using - problem solved. MSDN documentation looks to be incorrect.
chris