SQLiteConnection.Open keeps blocking if pooling enabled - c#

I'm using System.Data.SQLite (v1.0.104) in a multi-threaded C# application. When a thread want's to update the DB, it opens a new connection in a using statement (calling the method below) and executes its queries. This seems to work well with the connection string in the following example:
[MethodImpl(MethodImplOptions.Synchronized)]
private SQLiteConnection CreateSQLiteConnection()
{
var connection = new SQLiteConnection("Data Source=myDatabase.sqlite;Version=3");
connection.Open();
return connection;
}
However if I add Pooling=True to the connection string, I can observe the following: One thread is blocking on connection.Open(); indefinitely while the other threads are waiting to enter CreateSQLiteConnection. As far as I can tell from the debugger, at this point in time no thread is actually performing any kind of update to the db.
I already tried setting busy and default timeouts but that didn't change anything. I also know that the sqlite documentation suggests to avoid multiple threads altogether but that is currently not an option.
I've added the Synchronized attribute to avoid potential issues regarding multiple threads simultaneously calling SQLiteConnection.Open but it did not seem to make a difference.
Does anyone know what might cause SQLiteConnection.Open to behave like that or what I could try to get more details about this?

You can use SQLite Version 3 ==> .s3db,
public SQLiteConnection dbConnection = new SQLiteConnection(#"Data Source=E:\Foldername\myDatabase.s3db;");
SQLiteConnection cnn = new SQLiteConnection(dbConnection);
cnn.Open();
string sql = "SELECT * FROM Tble_UserSetUp";
DataSet ds = new DataSet();
SQLiteCommand mycommand = new SQLiteCommand(cnn);
mycommand.CommandText = sql;
SQLiteDataAdapter da = new SQLiteDataAdapter();
da.SelectCommand = mycommand;
da.Fill(ds);
cnn.Close();

Related

How to make a DataReader for global use

I have this code in my SQL Connect class.
public class SqlConnect
{
public string connectionString = ConfigurationManager.ConnectionStrings["cn"].ConnectionString;
private SqlConnection con;
public SqlCommand cmd;
private SqlDataAdapter sda;
private DataTable dt;
private SqlDataReader sdr;
public SqlConnect()
{
con = new SqlConnection(connectionString);
con.Open();
}
public void SqlQuery(string queryTxt)
{
cmd = new SqlCommand(queryTxt, con);
}
public DataTable QueryEx()
{
sda = new SqlDataAdapter(cmd);
dt = new DataTable();
sda.Fill(dt);
con.Close();
return dt;
}
public void NonQueryEx()
{
cmd.ExecuteNonQuery();
con.Close();
}
public void Reader()
{
sdr = cmd.ExecuteReader();
while(sdr.Read())
{
for (int i = 0; i < sdr.FieldCount; i++) ;
}
return;
}
Now, in my button I have this code. I'm having error saying cannot convert from Void to Object.
con = new SqlConnect();
con.SqlQuery("Select Department from Salary");
cboDept.Items.Add(con.Reader());
My question is how can I make this run? when I use the public datatable QueryEx I can only get the column name appear on the combobox (just the Column name). I'm searching here but I cant find any solution. How to make this code run?
You're looking for the DisplayMember and ValueMember properties.
Also, it's generally a bad practice to try to and manage your connection like this as it can potentially lead to leaked connections. In a WinForms environment, it's not as dangerous as it is in a web environment, but it is something to be cognizant of, especially if you have lots of WinForms clients talking to the same database. If you have an exception that is thrown in your NonQueryEx method from your code above and caught at a higher level, your SqlConnection will be left open.
See: https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/sql-server-connection-pooling?redirectedfrom=MSDN
The way you want to make your database calls is to wrap your construction of your SqlConnection object in a using block:
Example:
using (var cn = new SqlConnection(connectionString))
{
var cmd = new SqlCommand(...);
cmd.ExecuteNonQuery();
}
If you're wanting to use an abstraction layer to save yourself from typing, wrap your call within a using block within that layer. This is the #1 mistake that I see with ADO.Net code at new clients (in other words, this is an incredibly common mistake and don't let this criticism discourage you). ADO.Net manages connections behind the scenes. Opening and closing a connection does not actually terminate a connection to a database, it releases it to the pool so the next call to .Open or .Close can reuse that same connection. Holding onto it for any longer than necessary means that new connections may need to be created. Likewise, there is no guarantee when your SqlConnect() instances will be cleaned up by .Net, so if you have a repeated exception that is caught at a higher level, this can result in multiple connections waiting to be released until your SqlConnect class is garbage collected.

Modern way connect to SQL Server inside Script Task in SSIS 2012 and later

When you search the internet or SO how to connect to SQL database inside Script Task in SSIS you will find .NET v1.1ish code like this:
ConnectionManager cm;
System.Data.SqlClient.SqlConnection sqlConn;
System.Data.SqlClient.SqlCommand sqlComm;
cm = Dts.Connections["ADO.NET.SqlDB"];
sqlConn = (System.Data.SqlClient.SqlConnection)cm.AcquireConnection(Dts.Transaction);
sqlComm = new System.Data.SqlClient.SqlCommand("your SQL Command", sqlConn);
sqlComm.ExecuteNonQuery();
cm.ReleaseConnection(sqlConn);
I am looking for updated code that makes good use of later introduced .NET features.
For a start, how about the code below. Is this the current recommended way to connect to SQL Server inside Script Task in SSIS 2012 and later or do I miss something here?
ConnectionManager cm = Dts.Connections["ADO.NET.SqlDB"];
using (var sqlConn = (SqlConnection)cm.AcquireConnection(Dts.Transaction))
{
if (sqlConn.State != ConnectionState.Open)
sqlConn.Open();
using (var sqlComm = new SqlCommand(
String.Format("UPDATE myTab SET Processed = 4 where ID = '{0}'",
idNumber), sqlConn))
{
return sqlComm.ExecuteNonQuery();
}
}
Is the ReleaseConnection() still needed?
Is sqlConn.Open() really needed in an SSIS context?
One year later, and hopefully a little wiser, I settled with code like this:
ConnectionManager cm = Dts.Connections["ADO.NET.SqlServerDB"];
var sqlConn = (SqlConnection)cm.AcquireConnection(Dts.Transaction);
using (var sqlCmd = new SqlCommand(
"INSERT INTO apou_moodle_import(id_num, username, email) VALUES(#IdNum, #Username, #Email)",
sqlConn))
{
sqlCmd.CommandType = CommandType.Text;
sqlCmd.Parameters.AddWithValue("#IdNum", newUser.id_num);
sqlCmd.Parameters.AddWithValue("#Username", newUser.username);
sqlCmd.Parameters.AddWithValue("#Email", newUser.email);
int rowsAffected = sqlCmd.ExecuteNonQuery();
}
cm.ReleaseConnection(sqlConn);
So, I keep using ConnectionManager.ReleaseConnection, however, SqlConnection.Open & Close are not needed in an SSIS context. Plus, use Parameters to play safe.
Well, using structure allows you to automate disposing variables and handle it better. However, sqlConn is not a simple class, it is a ConnectionManager instance. When you start using it, you call AcquireConnection, when end - call ReleaseConnection. The ReleaseConnection may perform some housekeeping specific to this Data Source. Depending on ConnectionManager implementation, it may check at disposal whether ReleaseConnection was called or not and call it.
To my understanding, your code with using should be Ok in most cases. Problems may arise when you repeatedly open connections and do not release it - you might run of connection pool etc. I would wrap internals into try - finally block to ensure ReleaseConnection execution.

Why is my code leaking connections?

Question:
Why is the following code leaking connections ?
public System.Data.DataTable GetDataTable()
{
System.Data.DataTable dt = new System.Data.DataTable();
string strConnectionString = "Data Source=localhost;Initial Catalog=MyDb;User Id=SomeOne;Password=TopSecret;Persist Security Info=False;MultipleActiveResultSets=False;Packet Size=4096;";
System.Data.SqlClient.SqlConnectionStringBuilder csb = new System.Data.SqlClient.SqlConnectionStringBuilder(strConnectionString);
csb.IntegratedSecurity = true;
string strSQL = "SELECT * FROM T_Benutzergruppen";
using (System.Data.SqlClient.SqlConnection sqlcon = new System.Data.SqlClient.SqlConnection(csb.ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand(strSQL, sqlcon))
{
if (sqlcon.State != System.Data.ConnectionState.Open)
{
sqlcon.Open();
}
// First attempt
//System.Data.SqlClient.SqlDataAdapter sqlda = new System.Data.SqlClient.SqlDataAdapter("SELECT * FROM T_Benutzer", sqlcon);
//sqlda.Fill(dt);
cmd.ExecuteNonQuery();
}
if(sqlcon.State != System.Data.ConnectionState.Closed)
sqlcon.Close();
}
//sqlcon.ConnectionString = csb.ConnectionString;
// Second attempt
//System.Data.SqlClient.SqlDataAdapter sqlda = new System.Data.SqlClient.SqlDataAdapter("SELECT * FROM T_Benutzer", csb.ConnectionString);
//sqlda.Fill(dt);
return dt;
}
If I go into SQL-Server activity monitor, I see Session 68
SELECT * FROM T_Benutzergruppen
Additional question:
If question:
If I comment out everything except the ConnectionStringBuilder, and only execute the below code in this function, why does it leak a connection, too ?
// Second attempt
System.Data.SqlClient.SqlDataAdapter sqlda = new System.Data.SqlClient.SqlDataAdapter("SELECT * FROM T_Benutzer", csb.ConnectionString);
sqlda.Fill(dt);
Note:
The executenonquery makes no sense, it's just there for testing purposes.
If I let it run in the debugger, I see that
sqlcon.Close();
get's executed, so the problem is not the
if(sqlcon.State != System.Data.ConnectionState.Closed)
Connection Pooling. Don't worry about it.
This is normal behavior.
http://msdn.microsoft.com/en-us/library/8xx3tyca(v=vs.100).aspx
ADO.Net pools connections so that they can be re-used because they are relatively expensive to create.
Connecting to a database server typically consists of several time-consuming steps. A physical channel such as a socket or a named pipe must be established, the initial handshake with the server must occur, the connection string information must be parsed, the connection must be authenticated by the server, checks must be run for enlisting in the current transaction, and so on.
In practice, most applications use only one or a few different configurations for connections. This means that during application execution, many identical connections will be repeatedly opened and closed. To minimize the cost of opening connections, ADO.NET uses an optimization technique called connection pooling.
http://msdn.microsoft.com/en-us/library/8xx3tyca(v=vs.100).aspx
Also, there is no need to explicitly call .Close(). Your using block will call IDisposable.Dispose(), which will close the connection properly.

Why is this class member leaving a SQL connection open?

Further to my recent questions, I've now closed most of the connections that our web application was leaving open. However, the connection created by the function below remains open. Can anyone identify why it is not closing?
public DataTable GetSubDepartment(int deptId)
{
DataTable dt = new DataTable();
using (SqlConnection conn = new SqlConnection(Defaults.ConnStr))
{
SqlCommand cmd = new SqlCommand("proc_getDepartmentChild", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#dptParent", deptId));
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = cmd;
da.Fill(dt);
}
return dt;
}
* EDIT *
Following #HenkHolterman's comment:
I'm using SQL Server Management Studio Activity log to view the open connections. This one is listed as sleeping. SO what you say makes sense. Is there any way I can tell that this is a pooled connection rather than an open one?
Most probably because it went back to the connection pool.
Call
SqlConnection.ClearAllPools();
to clear the pool, then it should disappear. This could sometimes be useful, but is usually not needed.
I would assume that it's hanging in the connectionpool

Why isn't SqlConnection disposed/closed?

Given the method:
internal static DataSet SelectDataSet(String commandText, DataBaseEnum dataBase)
{
var dataset = new DataSet();
SqlConnection sqlc = dataBase == DataBaseEnum.ZipCodeDb
? new SqlConnection(ConfigurationManager.AppSettings["ZipcodeDB"])
: new SqlConnection(ConfigurationManager.AppSettings["WeatherDB"]);
SqlCommand sqlcmd = sqlc.CreateCommand();
sqlcmd.CommandText = commandText;
var adapter = new SqlDataAdapter(sqlcmd.CommandText, sqlc);
adapter.Fill(dataset);
return dataset;
}
Why is sqlc (the SqlConnection) not disposed/close after the calling method goes out of scope or sqlc has no more references?
EDIT 1:
Even wrapping it in using, I can still seeing the connection using (I have connection pooling turned off):
SELECT DB_NAME(dbid) as 'Database Name',
COUNT(dbid) as 'Total Connections'
FROM sys.sysprocesses WITH (nolock)
WHERE dbid > 0
GROUP BY dbid
EDIT 2:
Have some more debugging with help I got from here - the answer was the someone hard coded a connection string with pooling. Thanks for all the help - if I could, I would mark all the responses as answers.
C#'s garbage collection is non-deterministic but the language does provide a deterministic structure for resource disposal like this:
using (SqlConnection connection = new SqlConnection(...))
{
// ...
}
This will create a try/finally block which will ensure that the connection object is disposed regardless of what happens in the method. You really ought to wrap any instances of types that implement IDisposable in a using block like this as it will ensure responsibly resource management (of unmanaged resources like database connections) and also it gives you the deterministic control you are looking for.
Because c# is a garbage collected language, and garbage collection is not deterministic. The fact of it is that your sqlconnection is disposed. You just don't get to choose when.
Sql connections are a limited resource, and it's easily possible that you might create enough of them to run out. Write it like this instead:
internal static DataSet SelectDataSet(String commandText, DataBaseEnum dataBase)
{
var dataset = new DataSet();
using (SqlConnection sqlc = dataBase == DataBaseEnum.ZipCodeDb
? new SqlConnection(ConfigurationManager.AppSettings["ZipcodeDB"])
: new SqlConnection(ConfigurationManager.AppSettings["WeatherDB"]))
using (SqlCommand sqlcmd = sqlc.CreateCommand())
{
sqlcmd.CommandText = commandText;
var adapter = new SqlDataAdapter(sqlcmd.CommandText, sqlc);
adapter.Fill(dataset);
}
return dataset;
}
Though in this case you might get away with it, because the .Fill() method is a strange beast:
If the IDbConnection is closed before Fill is called, it is opened to retrieve data and then closed.
So that means the Data Adapter should be taking care of it for you, if you start out with a closed connection. I'm much more concerned that you're passing in your sql command as a plain string. There have to be user parameters in your queries from time to time, and this means you're concatenating that data directly into the command string. Don't do that!! Using the SqlCommand's Paramters collection instead.
I agree with all the answers here plus a connection may be a wider scope than just a method. When you need to use your existing connection in different places the scenario changes a bit. Always make sure to call Dispose for all objects that implement IDisposable after you are done using them. This is a good practice so you don't end up with unused objects that the garbage collector can't decide what to do with them.
It will be, after the garbage collection does it's job. Same goes for opening a file stream for writing without closing it. It might get 'locked' even though the codes went out of scope.
I believe it has something to do with SqlConnection pooling. What you can do, and we do often at work is wrap the entire call in a using statement which causes it to call the dispose() method, hense closing the connection and disposing of the object
You could then do something like this instead:
internal static DataSet SelectDataSet(String commandText, DataBaseEnum dataBase)
{
var dataset = new DataSet();
using(SqlConnection sqlc = dataBase == DataBaseEnum.ZipCodeDb
? new SqlConnection(ConfigurationManager.AppSettings["ZipcodeDB"])
: new SqlConnection(ConfigurationManager.AppSettings["WeatherDB"])) {
SqlCommand sqlcmd = sqlc.CreateCommand();
sqlcmd.CommandText = commandText;
var adapter = new SqlDataAdapter(sqlcmd.CommandText, sqlc);
adapter.Fill(dataset);
return dataset;
}
}

Categories

Resources