sql and pooled connection error - asp.net

Kindly look at the following code as this sample code gives an error when i hosted it on Hostexcellence , but locally it runs perfect, and the error is as the following:
Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached
SqlDataSource1.SelectCommand = "Select Top (3) * from News Order by NewsID Desc";
SqlDataSource1.DataSourceMode = SqlDataSourceMode.DataReader;
SqlDataReader r_News = (SqlDataReader)SqlDataSource1.Select(DataSourceSelectArguments.Empty);
DataGrid_News.DataSource = r_News;
r_News.Close();
DataGrid_News.DataBind();
So What's wrong with that code ??

See this: http://msdn.microsoft.com/en-us/library/s4yys16a(VS.71).aspx
Public Sub ConnectToSql()
Dim conn As New SqlClient.SqlConnection
' TODO: Modify the connection string and include any
' additional required properties for your database.
conn.ConnectionString = & _
"integrated security=SSPI;data source=SQL Server Name;" & _
"persist security info=False;initial catalog=northwind"
Try
conn.Open()
' Insert code to process data.
Catch ex As Exception
MessageBox.Show("Failed to connect to data source")
Finally
conn.Close()
End Try
End Sub
You should always include a finally clause to ensure that your connection is closed otherwise the connection will not be released (in case an exception occurs) and you will not have any more connections available.

Related

How to do Commit/rollback in sql server using VB.net

I'm working on an asp.net application which involves sql server as database. After writing huge function in vb.net, I had to select , insert and update different tables using one n other. I realized that, if all of this executed in one go then its a win win situation. If all of this doesn't go well then it would create a huge mess.
When we do DML operations in Oracle, we had to
commit;
rollback;
after every DML operation. My question is how do we do the same thing in sql server using VB.net.
My search leads to write a procedure #sql server. Inseration and delation will be done via sorted procedure. But I want it as normal operations like
SqlCommand("some query", connection")
Is it possible to do commit or rollback without using sorted procedures??
Thanks in advance!
You can also use a TransactionScope, which gives a bit cleaner code than managing transactions yourself.
Using transaction As NewTransactionScope()
Using connection As New SqlConnection(connectionString)
connection.Open()
Dim command As SqlCommand = connection.CreateCommand()
command.CommandText = _
"Insert into Region (RegionID, RegionDescription) VALUES (100, 'Description')"
command.ExecuteNonQuery()
command.CommandText = _
"Insert into Region (RegionID, RegionDescription) VALUES (101, 'Description')"
command.ExecuteNonQuery()
End Using
' If we do not run Commit(), e.g. an error occurs before we get here,
' the transaction will automatically roll back when we leave the Using block below
transaction.Commit()
End Using
You should use SqlTransaction.
Here is a shameless copy-paste from MSDN:
Private Sub ExecuteSqlTransaction(ByVal connectionString As String)
Using connection As New SqlConnection(connectionString)
connection.Open()
Dim command As SqlCommand = connection.CreateCommand()
Dim transaction As SqlTransaction
' Start a local transaction
transaction = connection.BeginTransaction("SampleTransaction")
' Must assign both transaction object and connection
' to Command object for a pending local transaction.
command.Connection = connection
command.Transaction = transaction
Try
command.CommandText = _
"Insert into Region (RegionID, RegionDescription) VALUES (100, 'Description')"
command.ExecuteNonQuery()
command.CommandText = _
"Insert into Region (RegionID, RegionDescription) VALUES (101, 'Description')"
command.ExecuteNonQuery()
' Attempt to commit the transaction.
transaction.Commit()
Console.WriteLine("Both records are written to database.")
Catch ex As Exception
Console.WriteLine("Commit Exception Type: {0}", ex.GetType())
Console.WriteLine(" Message: {0}", ex.Message)
' Attempt to roll back the transaction.
Try
transaction.Rollback()
Catch ex2 As Exception
' This catch block will handle any errors that may have occurred
' on the server that would cause the rollback to fail, such as
' a closed connection.
Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType())
Console.WriteLine(" Message: {0}", ex2.Message)
End Try
End Try
End Using
End Sub

InvalidOperationException: Timeout - recursive DB access

currently I have a serious problem with one of my web applications which runs into a Timeout Exception around half a dozen times a day.
Error: "The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached".
After a lot of googling I found out that the problem has something to do with unclosed connections. So I checked all functions that access the database in any way until I stumbled upon this one:
Private Sub getOrgas(ByVal orgID As String)
Dim Id = orgID
orgColl.Add(Id)
While (Not IsNothing(Id))
Dim conn = Database.DbWrapper.GetConnection(1, Integration.Mandanten.DatabaseType.AddonSQL)
Dim paras As New HashSet(Of System.Data.Common.DbParameter)
Dim orgatmp As String
paras.Add(New SqlClient.SqlParameter("#Id", orgID))
Dim dr = Database.DbWrapper.GetDataReaderFromStoredProcedure("stp_Orgas_Get", paras, conn)
While dr.Read
If Not valueInColl(CStr(dr(0))) Then
orgatmp = dr(0).ToString
orgColl.Add(orgatmp)
getOrgas(orgatmp)
End If
End While
dr.Close()
conn.Close()
Id = Nothing
End While
End Sub
As you can see this function executes a stored procedure and runs the results through a while loop where it calls the function again if a specific condition -valueInColl-. Now in that way it is possible that there are 20 or more open connections. It has nothing to do with the timeout-value which is set via the GetDataReaderFromStoredProcedure to 600 which actually should be enough. To be sure I doubled the value and will roll it out this evening. I'll see whether that helped within the next day then.
I believe the problem is that there are too many open connections at the same time, because of the recursive function, but I have no clue how to solve this.
I couldn't find anything as to how to edit the max connections. I'm not even entirely sure where have to set it. Is it the IIS, the DB itself or is it a programming-parameter (VB.net/ASP.NET).
Would be nice if you guys could help me out here.
[EDIT]
Ok, somebody had the idea to reuse the connection variable, but this won't work as the datareader is still running. As long as it is not closed I can't reuse the connection in any way and I can't close the datareader, because I might lose data if I do so. The while-loop for dr.read hasn't ended, yet ..
On the other hand I deleted the (pretty much useless) outer while and used an If-clause in exchange:
Private Sub getOrgas(ByVal orgID As String, ByVal con As DbConnection)
Dim Id = orgID
Dim conn As DbConnection
Dim tmpOrga As String
orgColl.Add(Id)
If Not IsNothing(Id) Then
If IsNothing(con) Then
conn = Database.DbWrapper.GetConnection(1, Integration.Mandanten.DatabaseType.AddonSQL)
Else
conn = con
End If
Dim paras As New HashSet(Of System.Data.Common.DbParameter)
paras.Add(New SqlClient.SqlParameter("#Id", orgID))
Dim dr = Database.DbWrapper.GetDataReaderFromStoredProcedure("stp_Orgas_Get", paras, conn)
While dr.Read
If Not valueInColl(CStr(dr(0))) Then
tmpOrga = dr(0).ToString
orgColl.Add(tmpOrga)
getOrgas(tmpOrga, conn)
End If
End While
dr.close()
conn.Close()
Id = Nothing
End If
End Sub
Is there any reason you cannot refactor things so that each recursion uses the same db connection?
I am not a VB coder but I would tackle it as follows
Change getOrgas() to take a connection parameter defaulting to 'nothing'.
Change the Dim conn line to if IsNothing(connParameter) conn = GetConnection() else conn := connParameter;
Change your recursion line to getOrgas(orgatmp, conn);
Test the F%%%% out of it.
I have just noticed the outer While Loop. Is it there just to confuse you ? How many times will it execute ? ...
I did wonder about the datareader -
try this - I see that your datareader needs to close before you recurse, so close it.
in pseudocode -
dim locallist = new list();
while dr.read
{
LocalList.Add dr.thing;
}
dr.close;
foreach(thing in locallist)
{
if Not ValueInColl(thing) Then
CallYourFunctionTRecursively()
end if;
}
Are you with me ?
If you are trying to put together all the members of a family then it depends which database system you are using how it is done, but look up 'Heirarchical queries' in your documentation.

Enterprise Library 5.0 Connection Pool Timeout

I have an old web application written in ASP.Net 2.0 Web Forms. I use the Data Access Block in Enterprise Library and have recently updated to version 5.0. The application is tiered, ie, UI layer, Service Layer, Data Layer. It also uses SQL Server 2008 for the data storage.
I have recently noticed that the following error is appearing when I run the application and browse to particular pages.
Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.
This tends to happen on pages that do a lot of separate reads from the database, maybe up to as many as 20 on one page.
Below shows snippets of my Data Access Class.
Public Class DataAccess
' create a private instance of the database factory
Private db As Database = DatabaseFactory.CreateDatabase()
Public Function ExecuteNonQuery(ByVal params() As SqlParameter, ByVal strSproc As String) As Integer
Dim intReturnValue As Integer = 0
Dim i As Integer
Dim cmd As DbCommand
cmd = db.GetStoredProcCommand(strSproc)
cmd.CommandTimeout = 120
For i = 0 To params.Length - 1
db.AddInParameter(cmd, params(i).ParameterName.ToString, params(i).DbType, params(i).Value)
Next
db.AddParameter(cmd, "return_value", DbType.Int32, ParameterDirection.ReturnValue, "", DataRowVersion.Default, 0)
db.ExecuteNonQuery(cmd)
intReturnValue = Int32.Parse(db.GetParameterValue(cmd, "#return_value"))
Return intReturnValue
End Function
Public Function ExecuteDataReader(ByVal params() As SqlParameter, ByVal SProc As String) As SqlDataReader
Dim i As Integer
Dim dr As SqlDataReader = Nothing
Dim cmd As DbCommand
cmd = db.GetStoredProcCommand(SProc)
cmd.CommandTimeout = 120
For i = 0 To params.Length - 1
db.AddInParameter(cmd, params(i).ParameterName.ToString, params(i).DbType, params(i).Value)
Next
dr = TryCast(DirectCast(db.ExecuteReader(cmd), RefCountingDataReader).InnerReader, SqlDataReader)
Return dr
End Function
Throughout my code, once I have finished with an SqlDataReader I always do something like this
If Not (drSource Is Nothing) Then
drSource.Close()
End If
Is there anything you folk can see that I am missing? Does it look like my code could be leaking connections or not closing properly?
I always thought the Garbage collector got rid of any open connections.
Any feedback or help would be greatly appreciated.
Thanks.
Your code is closing the data reader, but not the data connection associated with it.
Since your data reader is a SqlDataReader, it has a Connection property. You should be able to use that to close and dispose of the connection.

Query about Oracle Connections

I seem to be getting intermittent problems with my Oracle connection indicating something about a problem with semaphores which suggest that Oracle is somehow holding onto the connections instead of removing them after they have been used.
Here's the code and connection string I use:
Connection string: user id=user;password=password;data source=dataSource; Validate Connection=true;Min Pool Size=10;Connection Lifetime=5;Connection Timeout=60;Incr Pool Size=5;
And the code I use is this:
Dim OracleConn As New OracleConnection()
Dim DataTable As DataTable
Dim queryOracle As OracleCommand
Dim OracleDataAdapter As OracleDataAdapter
Dim connStr As String = "user id=user;password=password;data source=dataSource; Validate Connection=true;Min Pool Size=10;Connection Lifetime=5;Connection Timeout=60;Incr Pool Size=5;"
OracleConn.ConnectionString = connStr
Try
OracleConn.Open()
queryOracle = OracleConn.CreateCommand()
queryOracle.CommandText = "select * from table1"
DataTable = New DataTable()
OracleDataAdapter = New OracleDataAdapter(queryOracle)
OracleDataAdapter.Fill(DataTable)
table1.DataSource = DataTable.DefaultView
table1.DataBind()
Catch OracleEx As OracleException
Throw
Catch ex As Exception
Throw
Finally
If Not OracleConn Is Nothing And OracleConn.State = ConnectionState.Open Then
OracleConn.Close()
End If
End Try
Now my questions are:
Is this the best way of doing this?
I only "Close" my connection do I need to "Dispose" of it also?
I'm using Oracle.DataAccess.Client by the way.
Any help will be much appreciated
Try to put everything between Using.
Using oracleConn as OracleConnection = new OracleConnection()
'Your stuff goes here
End Using
the same goes for Commands.
P.S. There's is no need to catch Exception if they are just thrown again.
I suggest you to use using block (Execute Dispose in the end)
Using connection As New OracleConnection()
....
End Using
2 An application can call Close more than one time. No exception is generated.
If you called Dispose method SqlConnection object state will be reset. If you try to call any method on disposed SqlConnection object, you will receive exception.

.NET Framework Data Provider for Oracle multiple open connection

I have the below mentioned code in a seperate class file for establishing connection and carry out DB transactions. I have an issue where multiple connections being opened which sometime exceed the connection pool. When I stepped through the code I found that there are codes which call ConnectDB() in a loop without calling DisconnectDB(). But I expected that the condition OraConn.State = ConnectionState.Closed should handle the situation. Somehow the condition is always satisfied hence openning another set of connection. Can you suggest where am I going wrong and also what best practice can be adopted here?
Public Class Connection
Dim Str_conn As String = "Data Source=...; User=...; password=...; Min Pool Size=10; Max Pool Size=500;"
Public OraConn As OracleConnection
Dim cmd As OracleCommand
Dim dr As OracleDataReader
Dim data_adapt As OracleDataAdapter
Dim dt As DataTable
Dim ds As DataSet
Public Sub ConnectDB()
OraConn = New OracleConnection(Str_conn)
If OraConn.State = ConnectionState.Closed Then
OraConn.Open()
End If
End Sub
Public Sub DisconnectDB()
If OraConn.State = ConnectionState.Open Then
OraConn.Close()
End If
End Sub
Public Function get_dataset(ByVal query As String, ByRef ds As DataSet) As DataSet
data_adapt = New OracleDataAdapter(query, OraConn)
data_adapt.Fill(ds)
Return ds
End Function
Public Function get_datareader(ByVal query As String) As OracleDataReader
cmd = New OracleCommand(query, OraConn)
dr = cmd.ExecuteReader()
Return dr
End Function
Public Sub UpdateDB(ByVal query As String)
cmd = New OracleCommand(query, OraConn)
cmd.ExecuteNonQuery()
cmd.Dispose()
End Sub
The class is refered in other classes or directly in the aspx.vb pages like this.
Public Function InsertData(ByVal var1 As String, ByVal var2 As String) As Integer
conn.ConnectDB()
Dim qryInsert As String
qryInsert = " INSERT INTO TABLE VALUES ('" & var1 & "', "
qryInsert = qryInsert & var2 & "')"
Try
conn.UpdateDB(qryInsert)
Catch ex As OracleException
If ex.Code = 1 Then
updData(var1, var2)
ElseIf ex.Code = 2091 Then
msgprompt("Duplicate Unique Key!", "Warning")
End If
Finally
conn.DisconnectDB()
End Try
Return count
End Function
The connection is again opened in function updData(). While I understand that it has to be closed correctly but keeping tab on every developer is not possible. Hence I want to control it directly from the connection class by using the same connection but the condition If OraConn.State = ConnectionState.Closed is not helping.
UPDATE
I have put the code in UpdateDB under a Using block and removed call to ConnectDB and DisconnectDB from function like InsertData(...). It seems that the issue has been resolved. But I would like to know in case of exception will the connection remain open? and also OraConn is a public variable defined outside Using block so will it be disposed of by the GC?
Public Sub UpdateDB(ByVal query As String)
Using OraConn = New OracleConnection(Str_conn)
cmd = New OracleCommand(query, OraConn)
Try
OraConn.Open()
cmd.ExecuteNonQuery()
Catch ex As Exception
Throw
Finally
cmd.Dispose()
End Try
End Using
End Sub
You must close all the connections as soon as you are done with it, no matter what.
Suggestion:
The best practice for closing the connection is to do it in finally block. So that even if there is any error, catch it (log it if required) in catch block, and then connection will get close in finally block.
UPDATE
You can put one private static counter in your Connection class. When ever ConnectDB() is called you increment this counter and decrement it in every DisconnectDB(). Now in ConnectDB() you check the value of counter, if it exceeds a minimum threshold you throw error, by doing this way; you can come to know idle connection present in your code and refactor it. On production keep this threshold value high or ignore it in code.

Resources