vb.net - Mysql connections are not closing using Sub routines - mysql

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

Related

Can't open a connection to create a transaction

In MS-Access, I'm trying to get a connection so that I can run queries within a transaction.
Stripped down, the routine looks like this:
Public Sub SetConnection()
Dim ConnectionString As String
ConnectionString = CurrentDb.TableDefs("RandomTable").Connect
If conn Is Nothing Then
Set conn = New ADODB.Connection
PostToLog "SetConnection()", "Set Connection to " & ConnectionString
conn.Open ConnectionString ' Fails here
' conn.Open ' Gives the same error without specifying the connection
End If
Exit Sub
I can see that the connection string is exactly that set in the Linked Table Manager.
Then I use it like this
Public Sub Begin()
PostToLog "Begin()", "Start Begin"
SetConnection
If Not (conn Is Nothing) Then
PostToLog "Begin()", "Begin"
conn.BeginTrans
End If
End Sub
Public Sub Commit()
PostToLog "Commit()", "Start Commit"
If Not (conn Is Nothing) Then
PostToLog "Commit()", "Committing"
conn.CommitTrans
End If
CloseConnection
End Sub
Public Function GetConnection() As ADODB.Connection
' Use GetConnection() everywhere you want a connection. If in a transaction, these queries will automatically be included.
' The exception would be items that you do NOT want rolled back in case of failure, like logging.
If conn Is Nothing Then
' Set GetConnection = New ADODB.Connection
Set GetConnection = CurrentProject.Connection
Else
Set GetConnection = conn
End If
End Function
But the connection fails to open, conn isn't set, and everything happens outside a transaction.
The error is
Unspecified error [Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified: ConnectionString: ODBC;DSN=....
I've also tried
ConnectionString = CurrentProject.Connection.ConnectionString
but that looked like the connection string to the front end Access database, not the back end.
I can't find any excuse for why the linked tables can find the DSN, but can't when I create the connection.
Begin, Commit, Rollback are used like so....
objSQL.Begin ' Start transaction
' do some stuff that uses the conn connection
objSQL.Commit
Err:
objSQL.Rollback
Update:
Using conn = CurrentProject.Connection instead of creating a new ADODB connection appears to work. No errors are thrown.
But the changes do not appear, as if they all get rolled back.
Postgres doesn't allow for a dirty read, so I can't tell if the changes never happened or if they do and get reversed. And if they do get reversed, I can't tell if that is before or after the Commit or what exactly triggers it. I can see the SQL statements appearing to get executed on the Postgres connection.
I'm going to try exploring a little more what happens when I have a proper connection string, as demonstrated by #HansUp

How can I get the usernames in the account?

I'm making a VB.Net application which connects to a MySql database.
My application has many Accounts, and each account has several Users. I want to show this information, but the application just shows the first user of each account.
This is the code:
Public Function id(Label2 As String) As Double
Using connection = Getconnection()
connection.Open()
Using commandid = New MySqlCommand
commandid.Connection = connection
commandid.CommandText = "SELECT *FROM player.player
Where player.account_id=" & testString & V
Dim read = commandid.ExecuteReader
If read.HasRows Then
While read.Read
ActivateUser.namecharacter = read.GetString(2)
ActivateUser.job = read.GetString(3)
End While
read.Dispose()
Return True
Else
MessageBox.Show(" no ")
Return False
End If
connection.Close()
connection.Dispose()
End Using
End Using
End Function
How can I fix this to show all the users in the account?
Just create you connection in the method where you use it. Get rid of GetConnection just use a class level variable for the connection string.
Don't open a connection until directly before you use it.
You can include the command in the same using block by adding a comma at the end of the first line. Commands also need to be disposed. The command constructor can take the CommandText and the Connection as parameters.
What datatype is account_id in the database? I am going to guess it is a string type. Is V a variable or is it meant to be the string "V"? I am going to guess a hardcoded string. Where does testString come from? I am going to guess Label2 (terrible non-descriptive name) is teststring.
Never concatenate strings for you sql. Always use parameters.
A reader also needs to be closed and disposed so use Using blocks. The whole idea of accessing the database is to get in and out as quickly as possible. Don't set properties of ActivateUser and never show a message box. The user could have gone to lunch and your connection is left flapping in the breeze.
You have the datatype of your function as Double but your return statements have Booleans. Won't work.
It is not necessary to close and dispose the connection. The End Using does that.
Private ConStr As String = "Your connection string"
Public Function id(Label2 As String) As DataTable
Dim dt As New DataTable
Using connection As New MySqlConnection(ConStr),
commandid As New MySqlCommand("SELECT *FROM player Where account_id= #TestString;", connection)
commandid.Parameters.Add("#TestString", MySqlDbType.VarChar).Value = Label2 & "V"
connection.Open()
Using reader = commandid.ExecuteReader
dt.Load(reader)
End Using
End Using
Return dt
End Function
Then back in the User Interface code:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim dt = id(Label2.Text)
If dt.Rows.Count > 0 Then
ActivateUser.namecharacter = dt(0)(2).ToString
ActivateUser.job = dt(0)(3).ToString
Else
MessageBox.Show(" no ")
End If
End Sub
This makes a good separation of from your database code.

How to make a vb application work with a SQL database from any computer?

Most of my programming experience is c-based, so I don't have the clearest understanding of how SQL (specifically, the mySQL platform) works.
My vb.net application works completely fine on the computer I made it on. However, if I download it onto another computer, the mySQL connection fails to open. From what I've read on other StackOverflow posts, that's the fault of the connection string. My connection string looks something like this:
"server=xxx.xxx.xxx.xxx;uid=username;pwd=password;database=db;default command timeout=300"
Again, for the base computer, this works fine without any problems at all. It's when I run the program from a different computer when I run into trouble. Do I need to change the server number? I've tried doing that, but the program still doesn't work. Is there one more field I need to add into the string? Or do I need to configure mySQL settings in some way on each computer? I would like to change the program in a way that allows anybody to use it immediately upon download. Would any of the methods listed above work, or a completely different one entirely?
Thanks.
This is a simple class I use with MySQL. Replace everything in [bracket] by your values. if It's not working look at your firewall and also use MySQL WorkBench to create user/password/permission/schema. Make sure you can connect to your database with MySQL workbench then you know you have everything setup right.
Imports MySql.Data.MySqlClient
Public Class mysql
'Connection string for mysql
Public SQLSource As String = "Server=[x.x.x.x];userid=[yourusername];password=[yourpassword];database=[defaultdatabaseifany];"
'database connection classes
Private DBcon As New MySqlConnection
Private SQLcmd As MySqlCommand
Public DBDA As New MySqlDataAdapter
Public DBDT As New DataTable
' parameters
Public Params As New List(Of MySqlParameter)
' some stats
Public RecordCount As Integer
Public Exception As String
Function ExecScalar(SQLQuery As String) As Long
Dim theID As Long
DBcon.ConnectionString = SQLSource
Try
DBcon.Open()
SQLcmd = New MySqlCommand(SQLQuery, DBcon)
'loads params into the query
Params.ForEach(Sub(p) SQLcmd.Parameters.AddWithValue(p.ParameterName, p.Value))
'or like this is also good
'For Each p As MySqlParameter In Params
' SQLcmd.Parameters.AddWithValue(p.ParameterName, p.Value)
' Next
' clears params
Params.Clear()
'return the Id of the last insert or result of other query
theID = Convert.ToInt32(SQLcmd.ExecuteScalar())
DBcon.Close()
Catch ex As MySqlException
Exception = ex.Message
theID = -1
Finally
DBcon.Dispose()
End Try
Return theID
End Function
Sub ExecQuery(SQLQuery As String)
DBcon.ConnectionString = SQLSource
Try
DBcon.Open()
SQLcmd = New MySqlCommand(SQLQuery, DBcon)
'loads params into the query
Params.ForEach(Sub(p) SQLcmd.Parameters.AddWithValue(p.ParameterName, p.Value))
'or like this is also good
'For Each p As MySqlParameter In Params
' SQLcmd.Parameters.AddWithValue(p.ParameterName, p.Value)
' Next
' clears params
Params.Clear()
DBDA.SelectCommand = SQLcmd
DBDA.Update(DBDT)
DBDA.Fill(DBDT)
DBcon.Close()
Catch ex As MySqlException
Exception = ex.Message
Finally
DBcon.Dispose()
End Try
End Sub
' add parameters to the list
Public Sub AddParam(Name As String, Value As Object)
Dim NewParam As New MySqlParameter(Name, Value)
Params.Add(NewParam)
End Sub
End Class

SQL Queries and Threading

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.

MySql - An unhandled exception of type 'System.InvalidOperationException' occurred in System.Data.dll

I am using MYSQL database for that...I get this following Error...Please anyone can help me?
Imports System.Data
Imports MySql.Data Imports MySql.Data.MySqlClient
Public Class formLogin
Dim connStr As String = "server=localhost;user=root;database=ssknet;port=3306;password=;"
Dim connection As New MySqlConnection(connStr)
Private Sub btnLogin_Click(sender As Object, e As EventArgs) Handles btnLogin.Click
connection.Open()
Dim cmd As New MySqlCommand("SELECT * FROM user WHERE username=#username and password=#password", connection)
cmd.Parameters.Add("#username", MySqlDbType.VarChar).Value = txtUsername.Text
cmd.Parameters.Add("#password", MySqlDbType.VarChar).Value = txtPassword.Text
Dim adapter As New MySqlDataAdapter
Dim table As New DataTable
adapter.Fill(table)
If table.Rows.Count <= 0 Then
MessageBox.Show("Invalid Username or Password")
Else
MessageBox.Show("Login Success!")
End If
'cmd.ExecuteNonQuery()
connection.Close()
End Sub
End Class
I want to access database right now. Quick frnds
You are missing a critical step. You are not assigning any command to your adapter. It doesn't know how to query anything without a command
Dim adapter As New MySqlDataAdapter(cmd)
Next, according to the MySql Reserved KeyWords, user and password are reserved and to use them in a query as field names you should put backticks (ALT+096) around them. So the query should be written as
Dim cmd As New MySqlCommand("SELECT * FROM `user`
WHERE username=#username
AND `password`=#password", connection)
A part from this your code is good enough albeit there are a couple of thing to consider.
First, connection object should not be kept as global objects. This leads to many problems with the resources kept on the server and with closing/opening the connection when there is an error. Just create and discard the connection inside a using statement
Private Sub btnLogin_Click(sender As Object, e As EventArgs) Handles btnLogin.Click
Using connection = New MySqlConnection(connStr)
connection.Open()
.... all of your code except the close connection
End Using ' this close the connection also in case of exceptions
Second, you don't need an SqlDataAdapter and a datatable if you just want to check if the user/password exists
Dim reader = cmd.ExecuteReader()
if reader.HasRows then
MessageBox.Show("Login Success!")
Else
MessageBox.Show("Invalid Username or Password")
End If
Third, it is a great security risk to keep password in plain text inside your database and then using queries to retrieve it. You should use Salt and Hashing methods to store and retrieve password