an error keeping popping up in my codes (connection already open) - mysql

This error keeps popping up!!! An unhandled exception of type 'System.InvalidOperationException' occurred in MySql.Data.dll
Additional information: The connection is already open.
Dim cmd As MySqlCommand
con.Open()
Try
cmd = con.CreateCommand()
cmd.CommandText = "update animal_sale set #NOAB,#Amount,#Tax,#Total where Species=#Species"
cmd.Parameters.AddWithValue("#Species", TextBoxSpecies.Text)
cmd.Parameters.AddWithValue("#NOAB", TextBoxNo.Text)
cmd.Parameters.AddWithValue("#Amount", TextBoxAmount.Text)
cmd.Parameters.AddWithValue("#Tax", TextBoxTax.Text)
cmd.Parameters.AddWithValue("#Total", TextBoxTotal.Text)
cmd.ExecuteNonQuery()
load()
Catch ex As Exception
End Try
End Sub

It looks like you are not closing the connection after executing the query. You only have
con.Open()
and are not closing the connection after
cmd.ExecuteNonQuery()

Keep your database objects local to the method where they are used. Then you always know the state of a connection and can be sure they are closed and disposed. Using...End Using blocks do this for you even if there is an error. In this code both the connection and the command are covered by a single Using block. Note the comma at the end of the first Using line.
You can pass your connection string directly to the constructor of the connection.
You can pass your command text and the connection directly to the constructor of the command.
You Update sql command is not correct. You need to tell the server what fields to update. I had to guess at the names of the fields. Check you database for the correct names and adjust the code accordingly.
Please don't use .AddWithValue. See http://www.dbdelta.com/addwithvalue-is-evil/
and
https://blogs.msmvps.com/jcoehoorn/blog/2014/05/12/can-we-stop-using-addwithvalue-already/
and another one:
https://dba.stackexchange.com/questions/195937/addwithvalue-performance-and-plan-cache-implications
Here is another
https://andrevdm.blogspot.com/2010/12/parameterised-queriesdont-use.html
I had to guess at the datatypes and field size for the .Add method. Check you database for the correct values and adjust the code.
I converted the text box strings to the proper datatype here in the database code but normally these values would be parsed and converted before they reach this code.
Private Sub UpdateSale()
Using con As New MySqlConnection("Your connection string"),
cmd As New MySqlCommand("update animal_sale set nonab = #NOAB, amount = #Amount, tax = #Tax, total = #Total where species = #Species;", con)
cmd.Parameters.Add("#Species", MySqlDbType.VarChar, 100).Value = TextBoxSpecies.Text
cmd.Parameters.Add("#NOAB", MySqlDbType.Int32).Value = CInt(TextBoxNo.Text)
cmd.Parameters.Add("#Amount", MySqlDbType.Decimal).Value = CDec(TextBoxAmount.Text)
cmd.Parameters.Add("#Tax", MySqlDbType.Decimal).Value = CDec(TextBoxTax.Text)
cmd.Parameters.Add("#Total", MySqlDbType.Decimal).Value = CDec(TextBoxTotal.Text)
con.Open
cmd.ExecuteNonQuery()
End Using
End Sub

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.

Redefining/Re-setting parameters in MySQL query

I have the following code for inserting data into a table using a MySQL query in VB.NET
Dim MySqlCmdStr = "INSERT INTO tb_idlink(id1,id2) " &
"VALUES (#par1,#par2)"
MySqlCmd.CommandText = MySqlCmdStr
Dim checkedItem As Object
For Each checkedItem In CheckedListBox_1.CheckedItems
Try
MySqlCmd.Connection = MySqlConn
With MySqlCmd
.Parameters.AddWithValue("#par1", currentID)
.Parameters.AddWithValue("#par2", checkedItem.ToString())
End With
MySqlConn.Open()
MySqlCmd.ExecuteNonQuery()
MySqlConn.Close()
Catch ex As MySqlException
MessageBox.Show(ex.Message)
End Try
Next
My problem is if I have more than one box checked in CheckedListBox_1 then on the second loop an exception that says something like "parameter #par1 already defined". Is there a way I can re-define it? I'm not entirely familiar with the whole API.
Also, I'm not 100% sure if looping it is the best way to do this, but it's the first thing that popped into my head. Feel free to suggest an alternative way of doing this.
You dont redefine the parameters, you just supply a new value:
Dim SQL = "INSERT INTO tb_idlink (id1,id2) VALUES (#par1,#par2)"
Using dbcon As New MySqlConnection(MySQLConnStr)
Using cmd As New MySqlCommand(SQL, dbcon)
' define the parameter names and types
cmd.Parameters.Add("#par1", MySqlDbType.Int32)
cmd.Parameters.Add("#par2", MySqlDbType.Int32) ' ????
dbcon.Open()
For Each checkedItem In CheckedListBox1.CheckedItems
' provide the parameter values
cmd.Parameters("#par1").Value = currentID
cmd.Parameters("#par2").Value = Convert.ToInt32(checkedItem)
cmd.ExecuteNonQuery()
Next
End Using
End Using
Your code appears to reuse a global connection, that is ill-advised. The above uses Using blocks to create, use and and dispose of the DbConnection and DbCommand objects in the smallest scope possible
You should favor Add rather than AddWithValue so you can specify the datatype rather than forcing the the DB Provider guess and reduce the chance of data type mismatch errors.
These datatypes are a guess; CurrentId is not defined anywhere and given the names, both seem to be integers not strings.

How to pass CommandText to another MySqlCommand?

The title is a bit furviant, I'll try to explain better. So in my application I've two connection string, one for the local database, and another for the web database. This two database must be updated with the same records. Now in my app when I add a record in the local database I execute a function that pass the MySqlCommand object to another function that use another connection string for the web database. In this second function I need to execute the same operation already performed in the local database. Example code:
Function local database
Dim query = "INSERT INTO text_app (name, last_name)
VALUES(#namep, #last_namep)"
Dim MySqlCommand = New MySqlCommand(query, dbCon)
MySqlCommand.Parameters.AddWithValue("#namep", name.Text)
MySqlCommand.Parameters.AddWithValue("#last_namep", last_name.Text)
MySqlCommand.ExecuteNonQuery()
Sync.SyncOut(MySqlCommand) 'Pass the object to another function
Function web database (SyncOut)
Using dbCon As MySqlConnection = establishWebConnection()
Try
dbCon.Open()
Dim MySqlCommand = New MySqlCommand(query_command, dbCon)
MySqlCommand.ExecuteNonQuery()
Return True
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Using
Now query_command contain the MySqlCommand passed from the local function, dbCon is the new connection object.
When I perform the .ExecuteNonQuery on the SyncOut function I get this error:
Invalid Cast from 'MySqlCommand' type to 'String' type.
What I need is take the .CommandText property contained in the query_command, but I can't access to this property.
What exactly am I doing wrong? How I can achieve this?
The first thing to do is change the name of the variable that represent the MySqlCommand. I can't find any plausible reason to allow a confusion as this to spread along your code. Do not name a variable with the same name of its class even if the language permits, it is very confusing
Dim query = "INSERT INTO text_app (name, last_name)
VALUES(#namep, #last_namep)"
Dim cmd = New MySqlCommand(query, dbCon)
and, of course, change every reference to the old name with the new one.
Now in the declaration of SyncOut write
Public Sub SyncOunt(ByVal cmd As MySqlCommand)
...
' Do not forget to open the connection '
dbCon.Open()
Dim aDifferentCommand = cmd.Clone()
aDifferentCommand.Connection = dbCon
....

vb net set timeout period in connection string mysql

i have a program that proccess a huge database, it's around 4,8k records.. i'm populating the data into two 2d array, comparing it, then insert the result into database in form of new table..
and i also have two set of database, the smaller one with only 40 records and the biggest one with 4,8k records.. when i tested the smaller database, program runs correctly
but when i'm using the biggest one, the error occured.
i've already try to identified the connection leak, but it turned out that there isn't any.
i've already closed all the connection properly with dispose or close
but the first error message was the infamous ** timeout period period. . . max pool size was reached**
later after i dismiss the error message, another error message popped out the connection must be valid and open though i've already re-checked that problem
i'm using vs 2005 and i search to google that this error was the bug that occured in vs 2005, but i couldn't never properly find the solution that microsoft provided
so i'm thinking is there a way to fix this, like modified the connection function. what should i change in my code below?
Imports MySql.Data.MySqlClient
Public Class koneksi
Private Conn As MySqlConnection = Nothing
Public Function konek() As MySqlConnection
Dim ConnString As String
ConnString = ";server=localhost;user=root;password=;database=skripsi2;"
Try
Conn = New MySqlConnection(ConnString)
Conn.Open()
Catch ex As Exception
MessageBox.Show("Koneksi Error " + ex.Message)
End Try
Return Conn
End Function
End Class
*note: what i've already done yet is set the connection timeout to 0/300. set the pooling to true and give the max pool size = 200
but all that attempt was in vain.. nothing worked..
so could you please tell me how to fix this? i 've worked my brains out over one week and still got no solution for this
i'm using vb.net 2005 and mysql as database
'UPDATE CODE EXAMPLE CALLING THE CONNECTION FUNCTION
Dim resnode1 As String = "..."
CMD_resnode = New MySqlCommand(resnode1, conn.konek)
resnode = CMD_resnode.ExecuteReader()
Dim getmaxrow2 As String = "..."
CMD_maxrow2 = New MySqlCommand(getmaxrow2, conn.konek)
maxrow2 = Convert.ToInt32(CMD_maxrow2.ExecuteScalar())
CMD_maxrow2.Connection.Dispose()
maxrow22 = maxrow2 - 1
IF....THEN
....
resnode.read()
....
END IF
CMD_resnode.connection.dispose()
From my experience the timeout error is hardly about the connection. It rather has to do with the command the data adapter creates before it executes. If you're creating a data adapter by passing a sql query in a String then the adapter will create its own command. You have to get that command object from the SelectCommand property of the adapter and set its CommandTimeout.
Try:
mydataAdaptor.SelectCommand.CommandTimeout = xxxx
xxxx being some long time interval such as 60000 (1 hour)
As per the this stack-overflow thread . Its good practice to use close() method.
Dim resnode1 As String = "..."
CMD_resnode = New MySqlCommand(resnode1, conn.konek)
resnode = CMD_resnode.ExecuteReader()
Dim getmaxrow2 As String = "..."
CMD_maxrow2 = New MySqlCommand(getmaxrow2, conn.konek)
maxrow2 = Convert.ToInt32(CMD_maxrow2.ExecuteScalar())
CMD_maxrow2.Connection.Close()
maxrow22 = maxrow2 - 1
IF....THEN
....
resnode.read()
....
END IF
CMD_resnode.connection.Close()
If still facing the problem, try running SQL Queries on command line and check the execution time of your query.
It is difficult to diagnose this kind of problems, however, I can see in your example code the usual pattern with connections beeing created and leaked because they are not properly closed and returned to the connection pool. Your code force the creation of a new connection every time you call conn.konek and you seems to forget to close and dispose the instance created in the call.
Until the pool is exausted and you receive the fatal error.
A simple approach is to check your code where you call the conn.konek method and change it to something like this
' Just one call to konek and keep the instance for using in the enclosed block '
Using con = conn.konek
Dim resnode1 As String = "..."
CMD_resnode = New MySqlCommand(resnode1, con)
resnode = CMD_resnode.ExecuteReader()
....
Dim getmaxrow2 As String = "..."
CMD_maxrow2 = New MySqlCommand(getmaxrow2, con)
maxrow2 = Convert.ToInt32(CMD_maxrow2.ExecuteScalar())
maxrow22 = maxrow2 - 1
' Here the connection is closed and disposed.
End Using
In this way you create only one connection and encapsulate it in a Using Statement, at the End Using point the connection is automatically closed and disposed ALSO IF THE block of code internal at the using block raises an exception.
If you need to keep the DataReader open while you execute other commands then you could try
' Just one call to konek and keep the instance for using in the enclosed block '
Using con = conn.konek
Dim resnode1 As String = "..."
CMD_resnode = New MySqlCommand(resnode1, con)
resnode = CMD_resnode.ExecuteReader()
....
Using con1 = conn.konek
Dim getmaxrow2 As String = "..."
CMD_maxrow2 = New MySqlCommand(getmaxrow2, con1)
maxrow2 = Convert.ToInt32(CMD_maxrow2.ExecuteScalar())
maxrow22 = maxrow2 - 1
' Here the connection for the command is closed and disposed.
End Using
' Here the connection for the datareader is closed and disposed.
End Using