I have to execute several SQL queries and I want to use Threads for this, because this queries have to be executed every 1 second to update or get some different values of the database.
When I try to execute my code, I get the following Error:
WindowsApplication1.vshost.exe Error: 0 : There is already an open
DataReader associated with this Connection which must be closed first.
I have read on stackoverflow, that the Connection should ALWAYS be opened as late as possible and be closed as fast as possible.
Is there any solution for this Problem?
Here is my code:
Imports MySql.Data.MySqlClient
Imports System.Threading
Public Class Form1
Private server As String = Nothing
Private pass As String = Nothing
Private user As String = Nothing
Private port As String = Nothing
Private db As String = Nothing
Dim Thread1 As Thread
Dim Thread2 As Thread
Dim con As New MySqlConnection
Dim cmd As New MySqlCommand
Dim reader As MySqlDataReader
Public Sub New()
Me.server = "localhost"
Me.user = "root"
Me.pass = ""
Me.port = "3306"
Me.db = "diagnosedb"
cmd.Connection = con
con.ConnectionString = "Server = " & Me.server & ";
Port = " & Me.port & ";
Database = " & Me.db & ";
Uid = " & Me.user & ";
Pwd = " & Me.pass & ";"
Thread1 = New Thread(AddressOf Querie1)
Thread2 = New Thread(AddressOf Querie2)
Thread1.Start()
Thread2.Start()
End Sub
Private Sub Querie1()
cmd.CommandText = "UPDATE teileliste
SET verschleis = 500
WHERE ID = 1;"
Try
con.Open()
cmd.ExecuteNonQuery()
Catch ex As Exception
MsgBox(ex.Message)
Finally
con.Close()
End Try
End Sub
Private Sub Querie2()
cmd.CommandText = "UPDATE teileliste
SET verschleis = 0
WHERE ID = 20;"
Try
con.Open()
cmd.ExecuteNonQuery()
Catch ex As Exception
MsgBox(ex.Message)
Finally
con.Close()
End Try
End Sub
End Class
Create and close a new connection within the Querie1 and Querie2 methods. You can't have multiple concurrent operations going on with one connection. (Even if you could, you're closing the connection in both methods. One method might try to close it while the other is using it.)
The .NET Framework is good at managing connections. While you're opening and closing them in your code, behind the scenes it's actually keeping connections open for a brief period. This is called thread pooling. When you close a connection, it's actually kept open temporarily. When you open a new connection, it might actually give you the same one.
Most of the time we don't need to pay attention to that. All we do is create a new connection as close as possible to when we're going to open and use it, and then close (dispose) it as soon as possible.
Related
I'm new to Mysql databases. I created and connected successfully a database for the local server. But "A connection attempt failed..." error arise when trying to read data from a table. "Insert into ..." statement is working. I searched for whole web for the reason. Not success. Anyone can help, please. Thank in advance...
Complete error description:
A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
Relevant Code as follows:
following function Working and Connected successfully
Public Function Connect() As Boolean
Dim Status As Boolean
Try
conn.ConnectionString = "Server=" & Server & ";Port=3306;Database=" & DBName & ";User ID=" & UID & ";Password=" & Pwd & ";CharSet=utf8;"
conn.Open()
cmd.Connection = conn
If conn.State = ConnectionState.Open Then
Status = True
End If
Catch ex As Exception
ErrorMsg = ex.Message
Status = False
End Try
Return Status
End Function
Following Function returns the error...
Public Function getData(ByVal SQLStr As String) As MySql.Data.MySqlClient.MySqlDataReader
Dim tmpDR As MySql.Data.MySqlClient.MySqlDataReader
If conn.State = ConnectionState.Open Then
cmd.CommandText = SQLStr
tmpDR = cmd.ExecuteReader()
Else
MsgBox("Database not connected...", MsgBoxStyle.Exclamation, "Connection Error")
tmpDR = Nothing
End If
getData = tmpDR
End Function
Get rid of any class level database objects. Get rid of the Function Connect altogether. If you ever start to write
If conn.State = ConnectionState.Open Then
you should know you are doing it wrong.
Don't pass DataReader's around. The connection must remain open for them to function. Load a DataTable and pass that after the connection and command are disposed by the Using block.
If you intend to show a message box to the user, let exceptions bubble up to the user interface code.
Private ConStr As String = "Server=" & Server & ";Port=3306;Database=" & DBName & ";User ID=" & UID & ";Password=" & Pwd & ";CharSet=utf8;"
Public Function getData(ByVal SQLStr As String) As DataTable
Dim dt As New DataTable
Using conn As New MySqlConnection(ConStr),
cmd As New MySqlCommand(SQLStr)
conn.Open
dt.Load(cmd.ExecuteReader)
End Using
Return dt
End Function
As you can see, it only takes one simple line to create a connection. Connections are precious resources and should only be opened directly before the .Execute... and closed as soon as possible.
I'm currently writing a quick .net program that will allow users to query a Database
I've got it working to a point where it'll run SELECT statements that are hardcoded but when I get the "sql" variable to look at the contents in a text box (user input) it chucks up an error. This happens even when I copy and paste a SQL Query that works hardcoded into the user text box
This is my code:
Imports MySql.Data.MySqlClient
Public Class form_queueDepth
Public dbconn As New MySqlConnection
Public sql As String
Public dbread As MySqlDataReader
Public dbcomm As MySqlCommand
Private Sub form_queueDepth_Load(sender As Object, e As EventArgs) Handles MyBase.Load
dbconn = New MySqlConnection("Data Source=10.232.7.41;user id=Alex;password=abc;database=alexvb")
Try
dbconn.Open()
MsgBox("Succeed")
Catch ex As Exception
MsgBox("Unable to connect: " & ex.Message.ToString)
End Try
End Sub
Private Sub button_ExecuteQuery_Click(sender As Object, e As EventArgs) Handles button_ExecuteQuery.Click
sql = "SELECT * FROM depth_store WHERE ID < '10';"
dbcomm = New MySqlCommand(sql, dbconn)
MsgBox(sql)
Try
dbread = dbcomm.ExecuteReader()
While dbread.Read
listBox_QueryResults.Items.Add(dbread("Queue_Manager").ToString() & " | " & dbread("Queue").ToString() & " | " & dbread("DTime").ToString() & " " & dbread("QueueDepth").ToString())
End While
MsgBox("Success")
Catch ex As Exception
MsgBox("Error: " & ex.Message.ToString)
End Try
End Sub
End Class
SO the above code will work but the moment i change "sql = "SELECT * FROM depth_store WHERE ID < '10';" to "sql = (textBox_UserQuery).ToString" and then copy & paste the query It chucks up an error stating:
http://i66.tinypic.com/2pqnxmo.png
Any suggestions/help would be much appreciated - Let me know if any you require any other information
textBox_UserQuery is the name of an instance of a TextBox.
The ToString() method returns the name of the class
IE: System.Windows.Forms.TextBox.
If you want to use the content of a TextBox you need the property Text.
sql = textBox_UserQuery.Text
Said that, I hope that this 'program' is only for your internal use. If not you are giving away the capability to destroy an entire database. (DELETE FROM .....)
I'm using the code below in a module that I can then call from anywhere else in the program to manage my mysql database connection. I just call the dbExecute sub and then it in turn is supposed to open a DB connection using the manageConnection(true) statement and then close the connection using manageconnection(false). The problem I'm having is that after the dbC.Close statement the connection to the DB never drops so I just accumulate connections until the max hits at 104 and then I get a connection error. I have tried to add dbC.dispose, dbC = Nothing and nothing in that else statement for CloseConnection seems to matter. The connections remains open. I'm wondering if it's because I'm passing my msr into dbExecute ByRef, so it's holding the connection open for that dataset? If so how can I work around getting my DataReader passed back to the calling procedure? I'm trying to manage me DB connections after each DB call, but currently not doing a good job at it! Hope another set of eyes can help me understand my problem.
I'm using the following as an example of how I call the DB connection now:
Public Class frmLogin
Dim db As New DBCon
Dim msr As MySqlDataReader = Nothing
Dim Query As String
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles btnCheckConn.Click
Query = "Select username from db.userstable"
db.dbExecute(Query, msr)
******The following is the Module code****************
Imports MySql.Data.MySqlClient
Public Class DBCon
Dim dbC As MySqlConnection
Public Sub ManageConnection(ByVal CloseConnection As Boolean)
Try
dbC = New MySqlConnection("server=localhost; userid=****; password=****; database=****;")
If CloseConnection = True Then
If dbC.State = ConnectionState.Closed Then _
dbC.Open()
Else
dbC.Close()
End If
Catch ex As Exception
MsgBox("DB Connection failure:" & ex.Message)
End Try
End Sub
Public Sub dbExecute(ByVal q As String, ByRef msr As MySqlDataReader)
Try
ManageConnection(True) 'Open connection'
Dim msc As New MySqlCommand(q, dbC)
msr = msc.ExecuteReader
ManageConnection(False) 'Close connection'
Catch ex As Exception
MsgBox("Error " & ex.Message)
End Try
End Sub
Tried users suggestions below and was still seeing a connection hang when looking at the mysql workbench-performance-client connections. So I changed my ManageConnection code to the following below just to test and called it directly as :dbCon.ManageConnection (true) and as soon as the .open line fires I see a new connection to mysql, but the .close, .dispose and =nothing lines do not clear out that connection. Do I have something set wrong in mysql? If .open creates a new connection, I'm not sure why the very next line of .close wouldn't get rid of it. I do believe that's the root of my problem though. Hopefully someone has run into this before. Let me know your thoughts.
Public Sub ManageConnection(ByVal CloseConnection As Boolean)
Try
If CloseConnection = True Then
dbC = New MySqlConnection("server=localhost; userid=****; password=****; database=dbname;")
dbC.Open()
dbC.Close()
dbC.Dispose()
dbC = Nothing
Else
dbC.Close()
dbC.Dispose()
End If
Catch ex As Exception
MsgBox("DB Connection failure:" & ex.Message)
End Try
There are several ways to cope with these database connection leaks. Using ... End Using is probably the best. But you can also do dbC.Dispose() or set dbC = Nothing when you're done with a connection object.
The point is to, without fail, Dispose() the connection object when you're done with it. Using does that for you even if your program hits exceptions.
Try something like this in your main program. And stop using that ManageConnection sub. It's practically guaranteed to leak connections.
Using dbC as New MySqlConnection("server=localhost; userid=****; password=****; database=****;")
Dim msc As New MySqlCommand(q, dbC)
msr = msc.ExecuteReader
...
End Using
I have a pc program used by dozens of people, and with the increase in people connecting to a database, the program began to throw the error with a large number of database connections. I checked the database after each query creates a process that is in the database as "sleep" if you exceeded the number 50 is the above error crashes. How can I remedy this if the problem lies with the program or hosting?
Database screen ;
http://obrazki.elektroda.pl/5375287900_1423553806.png
Code:
Public Sub loginUser(ByVal sql As String)
Try
Dim maxrow As Integer
con.Open()
dt = New DataTable
With cmd
.Connection = con
.CommandText = sql
End With
da.SelectCommand = cmd
da.Fill(dt)
maxrow = dt.Rows.Count
If maxrow > 0 Then
Form1.Show()
Else
Label3.Text = ("Invalid Username or Password!")
Label3.Visible = True
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try
con.Close()
da.Dispose()
End Sub
Private Sub InsertData()
sql = "SELECT * from users WHERE login = '" & (username.Text) & "' and pass = '" & StringtoMD5(password.Text) & "'and banned = '" & 0 & "'"
loginUser(sql)
End Sub
When using database connections a special care should be used to correctly close and dispose these connections. If you don't do that correctly you end up with stale connections kept by your program and never reused by the pooling infrastructure of ADO.NET (See ADO.NET Connection Pooling)
The code in your example above has all the checks in place and should not be the cause of your problems but, are you sure that every where in your program you follow the same pattern without forgetting to dispose the involved objects?
The using statement is a life saver here because, EVEN in case of exceptions, you could be sure that the objects enclosed by the using statement are closed and disposed returning any unmanaged resources back to the system.
Another problem is your way to build SQL Commands concatenating strings. This leads directly to SQL Injection attacks and a very poor security standard for your application.
Said that, I think you should change your loginUser method to something like this
Public Sub loginUser(ByVal sql As String, ByVal parameterList as List(Of MySqlParameter))
Try
Dim maxrow As Integer
' local variables for connection, command and adapter... '
Using con = new MySqlConnection( ..connstring here.. )
Using cmd = con.CreateCommand()
con.Open()
With cmd
.Connection = con
.CommandText = sql
.Parameters.AddRange(parameterList.ToArray())
End With
Using da = new MySqlDataAdapter(cmd)
Dim dt = New DataTable
da.Fill(dt)
maxrow = dt.Rows.Count
If maxrow > 0 Then
Form1.Show()
Else
Label3.Text = ("Invalid Username or Password!")
Label3.Visible = True
End If
End Using
End Using
End Using
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
And call it with
Private Sub InsertData()
sql = "SELECT * from users " & _
"WHERE login = #uname " & _
"AND pass = #pwd " & _
"AND banned = '0'"
Dim parameterList = new List(Of MySqlParameter)()
parameterList.Add(new MySqlParameter("#uname", MySqlDbType.VarChar))
parameterList.Add(new MySqlParameter("#pwd", MySqlDbType.VarChar))
parameterList(0).Value = username.Text
parameterList(1).Value = StringtoMD5(password.Text)
loginUser(sql, parameterList)
End Sub
As I have said, just this change alone probably don't fix your problem. You should try to find in your program where you have a situation in which the connection is not properly closed and disposed. (and, at least, replace that code with the using statement)
I cannot seem to find the answer to my problem anywhere on the internet. I have seen solutions for others such as adding keys to appsettings etc, none of which have worked for me.
Imports Oracle.DataAccess.Client
Imports Oracle.DataAccess.Types
Imports System.Data
Sub Button1Click(sender As Object, e As EventArgs)
Dim oradb As String = "DATA SOURCE=INITIATE;PASSWORD=pASS;PERSIST SECURITY INFO=True;USER ID=uSER"
Dim conn As New OracleConnection(oradb)
Try
Dim sql As String = "select MEMRECNO from INIT.MPI_MEMHEAD where MEMIDNUM = '" + txtMRN.Text + "'"
Dim cmd As New OracleCommand(sql, conn)
cmd.CommandType = CommandType.Text
Dim dr As OracleDataReader = cmd.ExecuteReader()
dr.Read()
txt1.Text = dr.GetInt32(0)
Catch ex As Exception
richTextBox1.Text = richTextBox1.Text + vbCrLf + ex.Message
End Try
End Sub
Now, when I run this code, if I enter a value in the top 25 records (when visually looking at the table in Oracle) it returns the result. However, when I enter a value that might be record number 1 million, i get this error: "Operation is not valid due to the current state of the object."
Yes, the value does exist. Because if I run the exact same query in Oracle, I get the result.
This leads me to believe that the connection is timing out, closing, or there is a limit on how many rows can be returned using the Oracle Data Access Client.