I have started to receive an error with my VB.NET application:
Timeout Expired. The timeout 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.
I did have a few methods that were not correctly disposing of the connection. These have been fixed using Try and Finally.
However, this morning I received the error again whilst trying to open a simple report. I had MySQL Workbench open monitoring client connections. At the time I had 4 threads connected.
The MySQL DB kills connections that have been asleep for more than 15 seconds.
I am at a loss as to how I could have reached the max pool size, if indeed that is what the error is referring to.
Does the application read the max pool size setting and hold its own count of connections and throw the error when that number is reached, or does it get the number from the MySQL DB directly every time a new connection is opened?
Or could the error be due to something else?
EDIT 1
Some stats from MySQL Workbench
Threads Connected:3
Threads Running: 1
Threads Created: 250
Threads Cached: 5
Rejected (over limit): 0
Total Connections: 2822
Connection limit: 151
Aborted Clients: 2694
Aborted Connections: 84
Errors: 0
EDIT 2
Sample code calling and disposing of connection:
Public Shared Function GetCoursePaperCertificate(ByVal CourseTypeID As Integer) As String
Dim connx As New MySqlConnection(My.Settings.BMConnString)
Try
Dim cmdTextx = "Select `Cert` From `Courses` WHERE `ID`=#ID"
Dim cmdx As New MySqlCommand(cmdTextx, connx)
cmdx.Parameters.AddWithValue("#ID", CourseTypeID)
connx.Open()
Dim result = cmdx.ExecuteScalar
If result Is Nothing OrElse result Is DBNull.Value Then
Return String.Empty
Else
Return result
End If
Catch ex As Exception
Return String.Empty
Finally
connx.Dispose()
connx = Nothing
End Try
End Function
There are several things in your code.
First turn on Option Strict. The function is declared to return a string, but you are trying to return Object with Return result
Everything which implements a Dispose method ought to be used inside a Using block. This allows you to declare and initialize an object, use it and dispose of it at the end.
Parameters.Add is better than AddWithValue. The later forces the DB Provider to guess the datatype based on the data.
Depending on the load and whether that method is used a lot, you could load the data to a DataTable and do lookups on that rather than query the DB over and over.
The core issue is (probably) that you do not dispose of the DBCommand object. Look at the constructor you use:
Dim cmdx As New MySqlCommand(cmdTextx, connx)
The DBCommand object is passed a reference to the connection. Even though you explicitly dispose of the connection, cmdx still has a reference to it, and it was not disposed. Using blocks make it simple to be sure things are disposed:
Dim sql = "Select `Cert` From `Courses` WHERE `ID`=#ID"
Using dbCon As New MySqlConnection(MySQLConnStr)
Using cmd As New MySqlCommand(sql, dbCon)
cmd.Parameters.Add("#Id", MySqlDbType.Int32).Value = CourseTypeID
dbCon.Open()
Dim result = cmd.ExecuteScalar
If result Is Nothing OrElse result Is DBNull.Value Then
Return String.Empty
Else
Return result.ToString()
End If
End Using ' close, dispose of conn
End Using ' dispose of DBCommand
To reduce indentation, you can "stack" items into one Using block:
Using connx As New MySqlConnection(MySQLConnStr),
cmd As New MySqlCommand(sql, connx)
...
End Using
Note the comma at the end of the first line.
I'd be surprised if this was not the cause of your leak (of course all the code would need to be changed).
Related
How do I change connection and execute some query in my form load during run time? it's more like opening multiple connections simultaneously but how do I do that?
Example of the Database info:
EDIT: I do have the Query but I don't know how to open the other connection during run time. the structure of their database is the same so there's no problem when executing the query. The problem is just how do I change the connection during runtime without pressing anything.
Based on #jmcilhinney answer in an external forum. The adapter is using one connection for the Select and another connection for the Insert. The trick is setting the .AcceptChangesDuringFill to False The default changes the Added to Unchanged.
Private Sub UpdateADifferentDatabase()
Using cnSource As New MySqlConnection("First connection string"), cnDestination As New MySqlConnection("Second connection string")
Using selectCommand As New MySqlCommand("Select statement here", cnSource), insertCommand As New MySqlCommand("Insert statement here ", cnDestination)
Using da As New MySqlDataAdapter()
da.SelectCommand = selectCommand
da.InsertCommand = insertCommand
'The following allows the .DataRowState to remain as Added (normally it is changed to Unchanged by the .Fill method)
da.AcceptChangesDuringFill = False
Dim dt As New DataTable
da.Fill(dt)
da.Update(dt)
End Using
End Using
End Using
End Sub
My boyfriend and I have spent the last 2 hours trying to get this to work, we have tried putting all the data connections into try's, changing the the connections to gloabal's but whatever we do we end up back at the same problem. The page will load fine when loaded via localhost, but when we try to get in via debug it hits this error.
If we put the code that fails into a try it goes through each connection and then will load, but each part will have been caught in the catch.
An exception of type 'MySql.Data.MySqlClient.MySqlException' occurred in MySql.Data.dll but was not handled in user code
There is already an open DataReader associated with this Connection which must be closed first.
Here's the code, each sub or function that uses MySQL connection has a close in the same as this function. We are out of ideas to what it causing it, as only does it we try and enter debug in Visual Studio.
Public Function getID()
Dim cmd As New MySqlCommand()
Dim reader As MySqlDataReader
Dim rtr As Integer
cmd.CommandText = "MySQLSTATEMENT"
cmd.Connection = CON_STRING
Connection.Open()
reader = cmd.ExecuteReader
If (reader.HasRows()) Then
reader.Read()
rowID = reader.Item(0)
End If
Connection.Close()
reader.Close()
cmd.Dispose()
End Function
You Should Close reader first and then you can close the connection.
I would recommend Using Statement for connection that will take care of closings the connection.
As we know that DataAdapter opens and closes a Connection if it is not already open. But with my code it opens but not close..I am using MySql.Data.MySqlClient.MySqlDataAdapter, not sure what I am doing wrong. below is my code
Public Function GetDT(ByVal SqlQuery As String, ByVal ConString As String) As DataTable
Dim da As New MySql.Data.MySqlClient.MySqlDataAdapter(SqlQuery, ConString)
Dim ds As New DataSet
da.Fill(ds)
GetDT = ds.Tables(0)
da.Dispose()
ds.Dispose()
da = Nothing
ds = Nothing
End Function
I am using this connection string:"server=localhost;port=3306;user=someuser;pwd=somepassword;database=mydatabasename;Allow Zero Datetime=True;"
while debugging the code I found as soon as DataAdapter.fill executes its start a connection thread, but no where connection is getting close as thread remains in SLEEP state . Please check the below image.
Can any one please help me on this ?
Thanks
Its normal behavior because ADO.NET uses Connection Pooling with SQL Server by default. From MSDN:
http://msdn.microsoft.com/en-US/library/8xx3tyca(v=vs.110).aspx
Connecting to a database server typically consists of several
time-consuming steps. A physical channel such as a socket or a named
pipe must be established, the initial handshake with the server must
occur, the connection string information must be parsed, the
connection must be authenticated by the server, checks must be run for
enlisting in the current transaction, and so on.
In practice, most applications use only one or a few different
configurations for connections. This means that during application
execution, many identical connections will be repeatedly opened and
closed. To minimize the cost of opening connections, ADO.NET uses an
optimization technique called connection pooling.
Connection pooling reduces the number of times that new connections
must be opened. The pooler maintains ownership of the physical
connection. It manages connections by keeping alive a set of active
connections for each given connection configuration. Whenever a user
calls Open on a connection, the pooler looks for an available
connection in the pool. If a pooled connection is available, it
returns it to the caller instead of opening a new connection. When the
application calls Close on the connection, the pooler returns it to
the pooled set of active connections instead of closing it. Once the
connection is returned to the pool, it is ready to be reused on the
next Open call.
....
The connection pooler removes a connection from the pool after it has
been idle for approximately 4-8 minutes,...
The effect of "using" or "dispose" in the DataAdapter is the same. "using" ensures that dispose is executed, even if an exception happends. Is the same as using a try / finally statment and put the "dispose" on the finally section.
The connection only closes itself when you use a Using directive, the Using statement can be used on any object that implements the IDisposable interface.
In the Dispose() method of the DataAdapter the connection is closed before disposing the object.
using it correctly would be something like this.
Public Function GetDT(ByVal SqlQuery As String, ByVal ConString As String) As DataTable
Using da As New MySql.Data.MySqlClient.MySqlDataAdapter(SqlQuery, ConString)
Dim ds As New DataSet
da.Fill(ds)
GetDT = ds.Tables(0)
da.Dispose() //because you are now using a 'Using' statement, this method is not necessary anymore.
ds.Dispose()
da = Nothing
ds = Nothing
End Using
End Function
I am a beginner in vb and mysql... I am working on a project (vb 2010 express and mysql5.1) where there are two machines in a lan network. The application is installed on both the machines and the database is on one of the machines. Both connect to the DB using same user,(dr_admin). My problem is that the changes made from one machine doesn't get reflected in the other machine.
DBCon = New ADODB.Connection
DBCon.ConnectionString = ("Driver={MySQL ODBC 3.51 Driver};Server=Admin-PC; Database=dr_db; User=dr_admin;Password=dradmin;pooling=false;Option=3;")
DBCon.Open()
MsgBox(DBCon.State)
Try
Cmd = New ADODB.Command
Cmd.ActiveConnection = DBCon
Cmd.CommandText = "SEt autocommit=0;"
Cmd.Execute()
This is how i connect and i manually commit and rollback wherever needed.
I populate a list from the DB. The list is present on a panel. The data is loaded every time the panel becomes visible.
But the new data doesn't show up.
Then i added a bit of code to close current db connection and reopen again.
Public Sub reconnect_pr()
DBCon.Close()
MsgBox(DBCon.State)
DBCon = Nothing
DBCon = New ADODB.Connection
DBCon.ConnectionString = ("Driver={MySQL ODBC 3.51 Driver};Server=Admin-PC;Database=dr_db; User=dr_admin;Password=dradmin;pooling=false;Option=3;")
DBCon.Open()
MsgBox(DBCon.State)
Try
Cmd = New ADODB.Command
Cmd.ActiveConnection = DBCon
Cmd.CommandText = "SEt autocommit=0;"
Cmd.Execute()
Catch ex As Exception
MsgBox("autocommit error - Contact admin", MsgBoxStyle.OkOnly, "Patient Care")
End Try
End Sub
this is the code i use to retrieve the data from db.
Cmd = New ADODB.Command
Cmd.ActiveConnection = login_frm.DBCon
Cmd.CommandText = "select pat_no,pat_id,pat_name from pat_token_details order by pat_no;"
Rs = Cmd.Execute
exp_tod_pat_list.Items.Clear()
exp_tod_pat_list.Items.Add("None")
Do While Not Rs.EOF
v_token = Rs("pat_no").Value
v_pat_name = Rs("pat_name").Value
v_id = Rs("pat_id").Value
exp_tod_pat_list.Items.Add("Token id: " + v_token + " - " + v_pat_name + " ( " + v_id + " )")
Rs.MoveNext()
Loop
Catch ex As Exception
MsgBox("unable to fetch current token details", MsgBoxStyle.OkOnly, "Token")
End Try
Still it doesn't work.. But it gets reflected when i close the application and open it again.
Kindly help me understand the problem.
Thanks.
A short explanation of a reason of this behaviour:
In MySql the default isolation level is REPEATABLE READ.
In this mode (see this link for details: click me):
All consistent reads within the same transaction read the snapshot established by the first read. This convention means that if you issue several plain (nonlocking) SELECT statements within the same transaction, these SELECT statements are consistent also with respect to each other.
In easy words: if you issue, within the same transaction, the same SELECT statement several times, you will always get the same results, regardless of changes of database made by other sessions.
The session remembers, that the first SELECT within the transaction was run at the time X and "makes the snapshot of data" at the time X, then all subsequent selects will read this snaphshot at time X, but not current data.
See next link: (click me):
If the transaction isolation level is REPEATABLE READ (the default level), all consistent reads within the same transaction read the snapshot established by the first such read in that transaction. You can get a fresher snapshot for your queries by committing the current transaction and after that issuing new queries.
By commiting the transaction (or issuing a rollback of the transaction), you end this transaction, and a next SELECT (within a new transaction) will see fresh data.
If auto_commit is enabled, then all selects are always automatically commited - so you always see fresh data. But if you disable auto-commit, in repeatable-read (default) isolaton level, you must commit manually to see changes in the database.
Note: the above behaviour is true only for InnoDb tables. Other engines don't support ACID.
I have an Access application that is used as a TimeClock interface and to lookup pricing information. It is used on touchscreen computers and also on a Dell Latitude ST tablet which uses wireless exclusively.
The backend is SQL Server R2 2008 on a local Windows 7 "server" computer. I recently converted the application over to use forms bound to ADO recordsets in hopes that the application would be more resilient in the event that a disconnect occurs. I'm using a single, global ADO connection object. The tablet computer is configured to stay on all the time but it seems to lose connection occasionally. We could spend time troubleshooting the device and the network to make it more stable. However, I have hopes of being able to write my Access applications so they can be used over the WAN/Internet which will basically make network stability out of the picture and out of my control. I have chosen instead to focus on making this particular application (a fairly small one) more friendly with database disconnects and interruptions.
I've programmed a global function that basically checks to see if the ADO connection is open/connected. However, if I disconnect the network, the connection object still shows that State = adStateOpen.
I initially programmed a Test function to test the connection by opening a basic, single-record recordset. However, if the server was unavailable, this took way too long and seemed to cause a precipitation of errors beyond just the Test function (possibly some bad coding). I even changed connection TimeOut settings but it appeared that those timeouts were ignored since my test function would take about 15 (or was it 30) seconds to return in the event that the server really was unavailable.
I've now changed my function to close the connection every time and then re-open it. It seems so terribly inefficient but it is the only way I have found to make my application work properly after a server disconnect, without having to close out and open the application again. Server disconnects or network interruptions are actually very uncommon (basically non-existent), especially on the wired machines.
Public Function IsGConOpen(Optional bOpenCon As Boolean = True) As Boolean
IsGConOpen = False
If bOpenCon = True Then
Dim sConString As String
sConString = Config.ADOConString
If sConString = "" Then
Call InitGlobalSettings
sConString = Config.ADOConString
End If
If sConString = "" Then Exit Function
If gCon Is Nothing Then
Set gCon = New ADODb.Connection
Else
If gCon.State = adStateOpen Then
gCon.Close
End If
End If
With gCon
.Provider = "MSDataShape"
.ConnectionString = sConString
.CursorLocation = adUseClient
.ConnectionTimeout = 5
.CommandTimeout = 5
.Open
End With
If gCon.State = adStateOpen Then
IsGConOpen = True
End If
Else
If gCon Is Nothing Then
IsGConOpen = False
ElseIf gCon.State = adStateOpen Then
IsGConOpen = True
End If
End If
End Function
Here's a similar question (VB6 instead of Access) on a different forum. It appears to me that no solution was reached.
Is there a better way to manage my global ADO connection and detect server/network interruptions without having to close out the connection and reopen it every time?
I always preferred carrying out a ping check on the server's IP to see if I had a connection, this way I can limit the amount of time to wait on my ping check to be as short as I like, I didn't originally write the following code but did adapt it to my needs:
Public Function SystemOnline(ByVal IPAdd As String) As Boolean
Dim oShell, oExec As Variant
Dim strText, strCmd As String
strText = ""
strCmd = "ping -n 2 -w 1000 " & IPAdd
Set oShell = CreateObject("WScript.Shell")
Set oExec = oShell.Exec(strCmd)
Do While Not oExec.StdOut.AtEndOfStream
strText = oExec.StdOut.ReadLine()
If InStr(strText, "Reply") > 0 Then
SystemOnline = True
Exit Do
End If
Loop
End Function
And then I call it as:
If Not SystemOnline("11.111.11.111") Then
'Disconnected
Else
'Connected
End If
Perhaps you could fire this at set intervals to see how the connection is looking.
ADO is just another interface to ODBC which does not have a connection status. In ODBC you have the simple approach that you connect, do stuff, if stuff errors deal with the error.
The way I got round this problem in my MS Access program was to :-
Create connection
Do things ( select, updated, insert & delete )
If things error repeat process once and then display the error if it is still there.
This would work for basic statments however you may need to expand it a little further if you are sending multiple statments such as :-
Connect "con.open"
Begin transaction "con.BeginTrans"
Inset rows "con.Execute"
If all rows OK Commit the transaction "con.Commit"
The rows are only stored in the taget ODBC data source when you Commit so even if you get a network disconnection part way through inserting your rows this would that the data would not be stored. You could keep looping through the above if it's an automatted process or stop with a user error if the issue needs to be resolved before the code continues.