DataAdapter is not closing connection by itself - mysql

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

Related

How to open connection simultaneously with multiple connection?

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

MySQL Connection Pool Count

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).

VB.net "There is already an open DataReader associated with this Connection which must be closed first." when entering Visual Studio Debug

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.

VB.net MySQL connection check not working / slow

I have a program that's main function is to pull data from a MySQL database every x amount of time and adjust the GUI accordingly.
I have a two part problem in that the first thing that happens is that my GUI loads incredibly slowly in the background whilst the connection is being tried, you can literally see each label/box/image loading one by one until the MySQL check is complete.
A shoddy fix would be to add a me.Hide() before the function and then make it reappear after the results of the check have been displayed. Can you please take a look at the code? Will adding the MySQL check to a function and then calling it on Form1_Load help?
The second part of this is that my MySQL connection checker doesn't seem to work, now my host is accepting remote MySQL sessions and it does seem to think about connecting for a while... It's a good 6/7 seconds before the connection error message appears.
I pretty much followed guides and wrote the code myself, I understand each part but I think perhaps my ConnectionString is invalid.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
MaximizeBox = False
Dim conn As MySqlConnection
conn = New MySqlConnection
conn.ConnectionString = "Server=50.28.x.x; Port=3306; User id=xxx_admin; password=xxxx; Database=xxx_software; Connect Timeout=60;"
Try
conn.Open()
Catch myerror As MySqlException
MsgBox("There was an error connecting to the MySQL Database")
Label42.ForeColor = Color.Red
Label42.Text = "ERROR"
Timer1.Stop()
End Try
Timer1.Start()
Label37.Text = Now.ToShortTimeString()
End Sub
.Connect() is a blocking call, therefore you shouldn't put it into a sub that handles the Load event. Put it into Activated for example and check if it has run or not. You might also want to look into async/await which is officially available since VS2012. Though it's still not a good idea to put anything into Load that can cause an exception, because there is a problem with exception handling in this stage that occurs on 64bit machines running code in a 32bit version (to keep it simple).
The basic idea is to keep the UI-Thread (which handles the redrawing of your forms etc) free from "heavy" work, which means that the best results you will get when using some kind of "threading". And async/await is a very easy way to do it, because it keeps the usual program flow.
Public Class Form1
Private InitDone As Boolean = False
Private Async Sub Form1_Activated(sender As Object, e As EventArgs) Handles Me.Activated
If Not InitDone Then
InitDone = True
' simulate some blocking call
Await Task.Run(Sub() Threading.Thread.Sleep(10000))
Me.Text = "Ready to go"
End If
End Sub
End Class
Async is a decorator which simply "allows" you to use the await keyword in a method. This is needed because await is/was not a reserved word in C# and otherwise it might break old code.
The Await means that after the task has been scheduled, the UI-thread will continue and can redraw, process events etc. When the inner methode finished (usually in its own thread), the UI-thread "jumps" to the line directly after Await and executs that code. Nice an easy way to keep your app responsive AND to maintain a (seemingly) linear flow.
There is much more on async/await of course and you might need to invest some time to get used to it, but I would guess that it's worth any minute invested!

Detect Server or Network Disconnects

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.