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
Related
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
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
Is it possible to use an ADO connection string in VBA Access with failover partner option included?
My connection code looks something like this:
Public Function OpenADOConnection() As Boolean
On Error GoTo err_trap
' Opens Global ADO Connection if it isnt already open.
' Returns TRUE if connected
Dim boolState As Boolean
If gcnn Is Nothing Then
Set gcnn = New ADODB.Connection ' if the global has not been instantiated or has been destroyed
End If
If gcnn.state = adStateOpen Then
boolState = True ' already open, nothing else to do
Else
gcnn.ConnectionString = "Data Source=SQL01;Failover Partner=SQL02;Initial Catalog=DBNAME;Integrated Security=True"
gcnn.Open
If gcnn.state = adStateOpen Then
boolState = True
Else
boolState = False ' cannot open connection so return false
End If
End If
OpenADOConnection = boolState ' return the connection state
exit_here:
Exit Function
err_trap:
OpenADOConnection = False
Call MsgBox("Unable to connect to the database. Please notify Database Administrator!" & vbCrLf & _
"(This error CANNOT be logged!", vbCritical, "ADO Connection Failed:", "", 0)
200 Resume exit_here
End Function
Currently, it fails to open the connection so I'm not sure what I'm missing or even if it's possible to achieve this.
Essentially I want the connection to automatically failover without user interference and knowledge.
I don't see the Provider being defined anywhere in your connection string. That is a general problem.
I never used the failover options with ADO, but I'm pretty sure the old OLE DB Provider (SQLOLEDB) does not support them. Instead you should use the brand new Microsoft OLE DB Driver for SQL Server (msoledbsql).
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 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