every once and a while my application throws a connection to database lost error.
The database class I got from a tutorial site and is below, it works great except for the above error sometimes, im guessing its timing out, like if the person using it goes for a smoke break and comes back and tries to continue where they left off.
And of coarse being the normal end-user they close then error message THEN come get me to tell me they got an error.
But until the error comes up again i thought i would ask what part of this code could be changed to prevent that error
this is a firebird db server and a c# application
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Windows.Forms;
using FirebirdSql.Data.FirebirdClient;
namespace _0912111
{
class DatabaseConnection
{
private FbConnection conn;
private FbCommand sqlCommand;
private FbDataAdapter DB;
private DataSet DS = new DataSet();
public DatabaseConnection()
{
conn = new FbConnection("User=myuser;" + "Password=mypw;" + "Database=dbpath;" + "DataSource=serverip;" + "Port=dbport;" + "Dialect=3;" + "Charset=UTF8;");
}
public void showDbError(string theError)
{
MessageBox.Show("Could not connect to database\n\nError Details:\n" + theError);
}
public FbConnection Openconn()
{
if (conn.State == ConnectionState.Closed || conn.State == ConnectionState.Broken)
{
try
{
conn.Open();
}
catch (Exception e)
{
showDbError(e.Message.ToString());
}
}
return conn;
}
public FbConnection Closeconn()
{
if (conn.State == ConnectionState.Open)
{
conn.Close();
}
return conn;
}
public void nonQuery(string txtQuery)
{
FbCommand cmd = new FbCommand(txtQuery);
try
{
cmd.Connection = Openconn();
cmd.ExecuteNonQuery();
}
catch (Exception Ex)
{
showDbError(Ex.Message.ToString());
throw Ex;
}
finally
{
cmd = null;
}
}
public FbDataReader returnDataReader(string txtQuery)
{
FbCommand cmd = new FbCommand();
try
{
cmd.Connection = Openconn();
cmd.CommandText = txtQuery;
FbDataReader rd;
rd = cmd.ExecuteReader();
return rd;
}
catch (Exception Ex)
{
showDbError(Ex.Message.ToString());
throw Ex;
}
finally
{
cmd = null;
}
}
}
}
I would think that the code in her that says
if (conn.State == ConnectionState.Closed || conn.State == ConnectionState.Broken)
{
would prevent it??
Look, I suggest you to use using and rewrite your methods in a cleaner way, no reason to have another method to open and another to close connection, I'm not doing it anymore since longer than 5 years :D
also, no reason to do a ToString() on Ex.Message and also, notice, in C# you should throw exceptions with only throw not throw exc.
one of your methods would become this for example:
public void nonQuery(string txtQuery)
{
using(var conn = new FbConnection(GetMyConnectionString(...parameters...)))
{
using(var cmd = new FbCommand(txtQuery))
{
try
{
cmd.Connection = conn;
conn.Open();
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
showDbError(ex.Message);
throw;
}
}
}
}
I'm 100% with Davide Piras on this. (upvoted him)
Delete the "Openconn" and "Closeconn" methods from your DatabaseConnection class. Then change your queries to have using statements for the connection open and command execution.
The database drivers already know how to perform connection pooling. Maintaining an open connection in code is not just a waste of time, but a potential cause of issues like the one you are experiencing. Other issues it can cause are leaked memory and the ability to open further connections with the database server.
So, rewrite your code to use best practices for database access and the problem will go away.
I'll leave this example that speaks of the connection and some examples that I hope will help.
http://code.msdn.microsoft.com/Esempio-applicazione-dati-494c129a
Regards.
Related
I have a class and my MysqlConnection is in there:
public class DB
{
private static MySqlConnection _Connection;
public static MySqlConnection Connection
{
get
{
if(_Connection == null)
{
string cs = string.Format("SERVER={0}; DATABASE={1}; UID={2}; PWD={3};", SERVER_ADRESS, DATABASE, UID, PWD);
_Connection = new MySqlConnection(cs);
}
if(_Connection.State == System.Data.ConnectionState.Closed)
try
{
MessageBox.Show("MySQL Connection ist geschlossen. Öffne Sie");
_Connection.Open();
}
catch(MySqlException ex)
{
switch (ex.Number)
{
case 0:
MessageBox.Show("Verbindung zum Server konnte nicht hergestellt werden.");
break;
case 1045:
MessageBox.Show("Ungültiger Benutzername/Passwort.");
break;
default:
MessageBox.Show(ex.Message);
break;
}
}
return _Connection;
}
}
}
So i can use this connection in all the other classes with DB.Connection.
But now I get "DataReader is already open".
But all my DataReader's are in usings.
We start at my login page:
using (loginreader = cmd.ExecuteReader())
{
if (loginreader.Read())
{
DB.Connection.Close();
return true;
}
else
{
DB.Connection.Close();
return false;
}
loginreader.Close();
}
I guess this doesn't work. But the first Error Message after log in i get on another class on line 83:
DataTable schema = null;
using (var schemaCommand = new MySqlCommand("SELECT * FROM " + firmCustomerTablename, connection))
{
using (var reader = schemaCommand.ExecuteReader(CommandBehavior.SchemaOnly))
{
schema = reader.GetSchemaTable();
}
}
which is in a using too. So I don't understand why I get this Error. I guess closing the connections / the DataReaders dont work.
Before this change, i had a connection for every site. But my program had no good performance. So I decided to make 1 connection which is always Open and just call querys to this open connection. And now I get DataReader Errors.
Can someone explain me, why using is not closing the DataReader? And line 83 isn't a DataReader it's a var so i don't know why I get this Error at this line.
It sounds like your issues are regarding connection state management? I may not be fully understanding what you're asking but by design using statements within the context of connections will close the connection. They are syntactic sugar for try {} catch {} finally. Far too often I see examples of Connection objects, Command Objects, etc. not utilizing IDisposable and not being properly disposed/closed.
In this code, I don't see a connection being opened again for the command to execute.
DataTable schema = null;
using (var schemaCommand = new MySqlCommand("SELECT * FROM " + firmCustomerTablename, connection))
{
using (var reader = schemaCommand.ExecuteReader(CommandBehavior.SchemaOnly))
{
schema = reader.GetSchemaTable();
}
}
Here is a basic idea:
using (var conn = new SqlConnection(connectionString: ""))
{
conn.Open();
using (var cmd = new SqlCommand(cmdText: "cmdText", connection: conn))
{
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
//
}
}
}
}
Documentation: MSDN SqlConnection Class
I am new to the C# and My method showing a error in try catch connection is already open code as follow, when I closed it from Class method then Form getting a error invalid connection. here if put all code in FORM it is working. but here I get MysqlDataReader as a return value. how can I solve this error.
CLASS
//select all categories
public MySqlDataReader SelectCategory() {
try
{
MySqlCommand cmd = connection.CreateCommand();
cmd.CommandText = "SELECT * FROM categories WHERE online = 1";
connection.Open();
MySqlDataReader categories = cmd.ExecuteReader();
return categories;
}
catch (Exception ex) {
MessageBox.Show(ex.Message);
return null;
}
}
FORM
public void show()
{
MySqlDataReader rd = db.SelectCategory();
try
{
while (rd.Read())
{
listBox1.Items.Add(rd.GetString(1));
}
}
catch (Exception ex) {
MessageBox.Show(ex.Message);
}
}
I would use using which cares about disposing variables and closing connections.
CLASS:
public List<string> SelectCategory()
{
List<string> result = new List<string>();
string Command = "SELECT * FROM categories WHERE online = 1";
using (MySqlConnection mConnection = new MySqlConnection(ConnectionString))
{
mConnection.Open();
using (MySqlCommand cmd = new MySqlCommand(Command, mConnection))
{
using (MySqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
result.Add(reader.GetString(1));
}
}
}
}
return result;
}
FORM:
public void show()
{
try
{
foreach(string item in SelectCategory())
{
listBox1.Items.Add(item);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
The DataReader is an exceptional case used for retrieving data from the database, which always requires an open connection to get values from the DataReader. In your case you are passing the MySqlDataReader to the calling method, So you cannot close the connection from the called method since reader requires the opened connection. so the possibility for you is to Close the connection after closing the DataReader.
Another issue you may face is the connection problem(your current issue), From your code it is clear that you have not closed the connection, so when you call the method for first time, everything will be fine. when the second call triggers the connection's current state will be open so it will throws such exception when you tried to reopen the connection.
Don't worry you can use either one of the following to solve the issue(I'm not sure is such suggestions are valid answers for this community or not, forgive me if not)
Pass your UI control to the class method and Add items to the list
In this case the method is defined inside another class so its not possible to use the UI item there, So better option for is to pass the UI element, the ListBox to that method and make it filled using the reader. For that the code will be like this:
public MySqlDataReader SelectCategory(ListBox listBox1)
{
// fubo's answer here
}
Generate a method for closing connection after checking the connection state, and call that method when while completes its iterations.
The calling method will be like the following:
try
{
using (MySqlDataReader reader = db.SelectCategory())
{
while (reader.Read())
{
listBox1.Items.Add(reader.GetString(1));
}
}
db.CloseConnection(); // will be the method to close the connection
}
use DataTable instead for DataReader :
Get data to a DataTable and then bind the required list using that DataTable
always use finally to close your connection, whatever happen you must close your connection after opening.
public MySqlDataReader SelectCategory() {
try
{
MySqlCommand cmd = connection.CreateCommand();
cmd.CommandText = "SELECT * FROM categories WHERE online = 1";
connection.Open();
MySqlDataReader categories = cmd.ExecuteReader();
return categories;
}
catch (Exception ex) {
MessageBox.Show(ex.Message);
return null;
}
finally
{
if (connection != null && connection.State == ConnectionState.Open)
{
connection.Close();
connection.Dispose();
}
}
}
Hello Guys Below is my Code for accessing database. when i try to open site from more than one tab or i open it in debugging mode it gives error!
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
namespace DomeNameSpace
{
public class DAL
{
public static string _ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["xClassConnectionString"].ConnectionString;
public static SqlConnection _Connection = null;
public static SqlConnection Connection
{
get
{
//_Connection.Close();
//private static SqlConnection _Connection = null;
if (_Connection == null)
{
_Connection = new SqlConnection(_ConnectionString);
_Connection.Open();
return _Connection;
}
else if (_Connection.State != System.Data.ConnectionState.Open)
{
_Connection.Open();
return _Connection;
}
else
{
return _Connection;
}
}
}
public static DataSet GetDataSet(string sql)
{
try
{
SqlCommand cmd = new SqlCommand(sql, Connection);
SqlDataAdapter adp = new SqlDataAdapter(cmd);
// Connection.Close();
DataSet ds = new DataSet();
adp.Fill(ds);
return ds;
}
catch (SqlException err)
{
// Replace the error with something less specific.
// You could also log the error now.
throw new ApplicationException("Data error. " + err.Message.ToString());
}
finally
{
Connection.Close();
}
}
public static DataTable GetDataTable(string sql)
{
DataSet ds = GetDataSet(sql);
if (ds.Tables.Count > 0)
return ds.Tables[0];
return null;
}
public static int ExecuteSQL(string sql)
{
try
{
string BegSql = "BEGIN TRY BEGIN TRANSACTION ";
string EndSql = " COMMIT TRANSACTION END TRY BEGIN CATCH ROLLBACK TRANSACTION END CATCH";
string NewSql = BegSql + sql + EndSql;
sql = NewSql;
SqlCommand cmd = new SqlCommand(sql, Connection);
return cmd.ExecuteNonQuery();
}
catch (System.Exception ex)
{
return -1;
}
finally
{
Connection.Close();
}
}
}
}
But i am getting following here error
and output says
what seems to be the problem?
A single, static database connection is a famously bad idea. It essentially makes your application single-threaded, which a web application by nature is not.
Don't centralize your connection object like this. Creating a connection object is not a resource-intensive operation. And opening the connection itself isn't particularly resource-intensive, the connection pool takes care of most of the heavy lifting for you and is very well optimized.
Create your database connection objects when you need them, as close to where you use them as possible, and dispose of them as soon as you're done with them. In general, a pattern similar to this:
public void SomeMethodWhichConnectsToDB()
{
using (var connection = new SqlConnection())
using (var command = new SqlCommand())
{
// do something with the connection, execute the command, etc
}
}
You can encapsulate the creation of the connection into a (non-static) method to avoid code duplication and whatnot. But don't re-use the same connection object in memory over and over. Create it, use it, destroy it in as little time as possible.
The error is pretty self-explanatory but the reason you are running into this sort of problem is because the connection object is static, which means, that you are sharing this instance for all the calls you make to the database - all threads executing any kind of data access will use the same connection, which you clearly don't want.
What you should do is create the instance of a SQL Connection inside every method or create a Utility class that returns a new instance for every call.
For example:
public class DBUtility
{
public static DbConnection GetOpenConnection()
{
var conn = new DBConnection(connectionString); //or whatever type
conn.Open();
return conn;
}
}
Now in your methods:
public static int ExecuteSQL(string sql)
{
using (var conn = DBUtility.GetOpenConnection())
{
....
}
}
I am getting Database is locked exception from SQLite for some queries only.
Below is my code:
When I execute any select statement it works fine.
When I am executing any write statement on Jobs Table it also works fine.
This works fine:
ExecuteNonQuery("DELETE FROM Jobs WHERE id=1");
But the same way if I am executing queries for Employees table it is throwing an exception that database is locked.
This throws Exception:
ExecuteNonQuery("DELETE FROM Employees WHERE id=1");
Below are my functions:
public bool OpenConnection()
{
if (Con == null)
{
Con = new SQLiteConnection(ConnectionString);
}
if (Con.State == ConnectionState.Closed)
{
Con.Open();
//Cmd = new SQLiteCommand("PRAGMA FOREIGN_KEYS=ON", Con);
//Cmd.ExecuteNonQuery();
//Cmd.Dispose();
//Cmd=null;
return true;
}
if (IsConnectionBusy())
{
Msg.Log(new Exception("Connection busy"));
}
return false;
}
public Boolean CloseConnection()
{
if (Con != null && Con.State == ConnectionState.Open)
{
if (Cmd != null) Cmd.Dispose();
Cmd = null;
Con.Close();
return true;
}
return false;
}
public Boolean ExecuteNonQuery(string sql)
{
if (sql == null) return false;
try
{
if (!OpenConnection())
return false;
else
{
//Tx = Con.BeginTransaction(IsolationLevel.ReadCommitted);
Cmd = new SQLiteCommand(sql, Con);
Cmd.ExecuteNonQuery();
//Tx.Commit();
return true;
}
}
catch (Exception exception)
{
//Tx.Rollback();
Msg.Log(exception);
return false;
}
finally
{
CloseConnection();
}
}
This is the Exception:
At line 103 : Cmd.ExecuteNonQuery();
Exception Found:
Type: System.Data.SQLite.SQLiteException
Message: database is locked
database is locked
Source: System.Data.SQLite
Stacktrace: at System.Data.SQLite.SQLite3.Step(SQLiteStatement stmt)
at System.Data.SQLite.SQLiteDataReader.NextResult()
at System.Data.SQLite.SQLiteDataReader..ctor(SQLiteCommand cmd, CommandBehavior behave)
at System.Data.SQLite.SQLiteCommand.ExecuteReader(CommandBehavior behavior)
at System.Data.SQLite.SQLiteCommand.ExecuteNonQuery()
at TimeSheet6.DbOp.ExecuteNonQuery(String sql) in d:\Projects\C# Applications\Completed Projects\TimeSheet6\TimeSheet6\DbOp.cs:line 103
Somewhere along the way a connection is getting left open. Get rid of OpenConnection and CloseConnection and change ExecuteNonQuery to this:
using (SQLiteConnection c = new SQLiteConnection(ConnectionString))
{
c.Open();
using (SQLiteCommand cmd = new SQLiteCommand(sql, c))
{
cmd.ExecuteNonQuery();
}
}
Further, change the way you read data to this:
using (SQLiteConnection c = new SQLiteConnection(ConnectionString))
{
c.Open();
using (SQLiteCommand cmd = new SQLiteCommand(sql, c))
{
using (SQLiteDataReader rdr = cmd.ExecuteReader())
{
...
}
}
}
Do not attempt, to manage connection pooling on your own like you are here. First, it's much more complex than what you have coded, but second, it's handled already inside the SQLiteConnection object. Finally, if you're not leveraging using, you're not disposing these objects properly and you end up with issues like what you're seeing now.
You can use 'using' statement as below, that will make sure connection & command disposed correctly even in exception
private static void ExecuteNonQuery(string queryString)
{
using (var connection = new SQLiteConnection(
ConnectionString))
{
using (var command = new SQLiteCommand(queryString, connection))
{
command.Connection.Open();
command.ExecuteNonQuery();
}
}
}
You should close your DataReader before attempting to write any data to the database. Use:
dr.Close();
after you finish using the DataReader.
In my case it was very stupid of me, I was making changes in SQLite browser and did not click on write changes, which locked the DB to be modified by the services. After I clicked the Write changes button, all the post request worked as expected.
A lot of helpful posts here for folks that may have forgotten to clean up a dangling connection, but there is another way this can happen: SQLite does not support concurrent INSERTs; if you issue two INSERTs at the same time the will be processed in serial. When the INSERTs are quick this is fine, but if an INSERT takes longer than the timeout the second INSERT can fail with this message.
I had this happen when I used a long running transaction to accumulate a bunch of INSERTs into one big commit. Basically I locked the database from any other activity during the transaction. Switching to journal_mode=WAL will allow concurrent writes and reads, but not concurrent writes.
I got rid of the long running transaction and let each INSERT autocommit, and that solved my problem.
Mine was caused by not closing a SqliteDataReader when calling HasRows().
I had this:
using (SQLiteConnection connection = new SQLiteConnection(DbPath))
{
connection.Open();
string sql = $"SELECT * FROM ...";
using (SQLiteCommand command = new SQLiteCommand(sql, connection))
{
return command.ExecuteReader().HasRows;
}
connection.Close();
}
But needed to put a using around the ExecuteReader like so:
using (SQLiteDataReader reader = command.ExecuteReader())
{
return command.ExecuteReader().HasRows;
}
Even though the DbConnection was being disposed and re-created each time the db was still being kept locked by the reader.
I was also getting the same error here:
if (new basics.HindiMessageBox(HMsg, HTitle).ShowDialog()==true)
{
SQLiteConnection m_dbConnection = new SQLiteConnection(MainWindow.con);
m_dbConnection.Open();
sql = "DELETE FROM `users` WHERE `id`=" + SelectedUser.Id;
command = new SQLiteCommand(sql, m_dbConnection);
command.ExecuteNonQuery();
m_dbConnection.Close();
LoadUserDG();
}
but when I just changed SQLiteConnection declaration location
public partial class User : Window
{
SQLiteCommand command;
string sql;
AddUser AddUserObj;
List<basics.users> usersList;
basics.users SelectedUser;
SQLiteConnection m_dbConnection;
// ...
private void DeleteBtn_Click(object sender, RoutedEventArgs e)
{
// ...
if (new basics.HindiMessageBox(HMsg, HTitle).ShowDialog()==true)
{
m_dbConnection = new SQLiteConnection(MainWindow.con);
m_dbConnection.Open();
sql = "DELETE FROM `users` WHERE `id`=" + SelectedUser.Id;
command = new SQLiteCommand(sql, m_dbConnection);
command.ExecuteNonQuery();
m_dbConnection.Close();
LoadUserDG();
}
}
Everything is fine now.
I hope this may work for you, too.
If someone can say how this happened, I would like to know the details to improve my knowledge, please.
I had the same issue when loading a lot of data to different tables from multiple threads.
When trying to do the inserts I was getting database locked because the program was doing too many insert too fast and SQLite didn't have time to complete each transaction before another one came.
The insert are done through threading because I didn't want the interface to be locked and wait for the insert to be done.
My solution is to use BlockingCollection with ThreadPool.QueueUserWorkItem.
This allows me to free the interface while doing the inserts.
All the insert are queued and executed in FIFO (First In First Out) order.
Now the database is never locked while doing any SQL transaction from any thread.
public class DatabaseQueueBus
{
private BlockingCollection<TransportBean> _dbQueueBus = new BlockingCollection<TransportBean>(new ConcurrentQueue<TransportBean>());
private CancellationTokenSource __dbQueueBusCancelToken;
public CancellationTokenSource _dbQueueBusCancelToken { get => __dbQueueBusCancelToken; set => __dbQueueBusCancelToken = value; }
public DatabaseQueueBus()
{
_dbQueueBusCancelToken = new CancellationTokenSource();
DatabaseQueue();
}
public void AddJob(TransportBean dto)
{
_dbQueueBus.Add(dto);
}
private void DatabaseQueue()
{
ThreadPool.QueueUserWorkItem((param) =>
{
try
{
do
{
string job = "";
TransportBean dto = _dbQueueBus.Take(_dbQueueBusCancelToken.Token);
try
{
job = (string)dto.DictionaryTransBean["job"];
switch (job)
{
case "SaveClasse":
//Save to table here
break;
case "SaveRegistrant":
//Save Registrant here
break;
}
}
catch (Exception ex)
{//TODO: Handle this exception or not
}
} while (_dbQueueBusCancelToken.Token.IsCancellationRequested != true);
}
catch (OperationCanceledException)
{
}
catch (Exception ex)
{
}
});
}
}
The inserts are done this way, but without the queuing I was still getting the lock issue.
using (SQLiteConnection c = new SQLiteConnection(BaseDal.SQLiteCon))
{
c.Open();
using (SQLiteCommand cmd = new SQLiteCommand(sql, c))
{
cmd.ExecuteNonQuery();
}
c.Close();
}
I keep getting this error randomly:
System.Web.Services.Protocols.SoapException: System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> System.InvalidOperationException: The connection was not closed. The connection's current state is connecting.
The code it's complaning about is below:
DataSet ds = new DataSet();
cn = new SqlConnection(GetDBConnectionString());
using (cn)
{
try
{
SqlCommand cmd = new SqlCommand("uspGetNavigationItems", cn);
cmd.CommandType = CommandType.StoredProcedure;
cn.Open();
SqlDataAdapter adp = new SqlDataAdapter(cmd);
adp.Fill(ds, "NavItems");
}
catch (Exception ex)
{
ds = null;
throw ex;
}
finally
{
if (cn.State != ConnectionState.Closed)
{
cn.Close();
}
}
}
if (ds.Tables.Count > 0)
{
if (ds.Tables[0].Rows.Count > 0)
{
return ds.Tables[0];
}
else
{
return null;
}
}
else
{
return null;
}
I don't understand where the problem is, why it's saying the connection is connecting, when I have a finally to clean it up. Is it because i'm using Finally to close and the using statement, which is supposed to close it as well? Again this happens randomly not always, that's why i'm not sure what's going on.
Thank you.
You don't need to close the connection in finally if you're using the using-statement since it will close it from dispose implicitely.
Rule of thumb: use the using-statement for every class implementing IDisposable(like Connections,DataAdapter,Commands). On the other hand, a DataSet or a DataTable does not implement it and does not need to be disposed manually or via using.
But change:
cn = new SqlConnection(GetDBConnectionString());
using (cn)
{
//code
}
to:
using (var cn = new SqlConnection(GetDBConnectionString()))
{
//code
}
This will be translated to:
SqlConnection cn = new SqlConnection(GetDBConnectionString());
try
{
//code
}
finally
{
if (cn != null)
((IDisposable)cn).Dispose();
}
Sidenote: throw instead of throw ex would keep the stacktrace. With throw ex you're hiding the original source of the exception.
https://stackoverflow.com/a/22628/284240
Take away that finally block as your using statement will take care of your Connection Closing