We have some client code which is using the SqlConnection class in .NET to talk to a SQLServer database. It is intermittently failing with this error:
"ExecuteReader requires an open and available Connection. The connection's current state is Closed"
The "temporary" solution is to reboot the process, after which everything works - however, that's obviously unsatisfactory.
The code is keeping a cache of SqlConnection instances, one for each database.
We'd like to re-write the code, but before I do, I need to know a few things:
My first question is: Is it inefficient to repeatedly connect and disconnect SqlConnection objects, or does the underlying library perform connection pooling on our behalf?
// Is this bad/inefficient?
for(many-times)
{
using(SQLConnection conn = new SQLConnection(connectionString))
{
// do stuff with conn
}
}
Because our code does not do the above, what seems the likely cause of the problem is that something happens to the underlying SQLServer database during the "lifetime" of the connection that causes the connection to be closed...
If it turns out that it is worthwile to "cache" SqlConnection objects, what is the recommended way to handle all errors that could be resolved simply by "reconnecting" to the database. I'm talking about scenarios such as:
The database is taken offline and brought back online, but the client process had no open transactions while this was happening
The database was "disconnected", then "reconnected"
I notice that there is a "State" property on SqlConnection... is there an appropriate way to query that?
Finally, I have a test SQLServer instance set up with full access rights: how can I go about reproducing the exact error "ExecuteReader requires an open and available Connection. The connection's current state is Closed"
No, it's not inefficient to create lots of SqlConnection objects and close each of them when you're done. That's exactly the right thing to do. Let the .NET framework connection pooling do its job - don't try to do it yourself. You don't need to do anything specific to enable connection pooling (although you can disable it by setting Pooling=false in your connection string).
There are many things that could go wrong if you try to cache the connection yourself. Just say no :)
You should enable connection pooling on your connection string. In that case the runtime will add back your connections to the 'pool' when you close them, instead of really disconencting. When a 'new' connection is taken out of the pool it will be reset (ie. sp_reset_connection is called ) then presented to your application as a brand new, fresh connection. The pool is handling transparently such cases as if the connection is closed while idling in the pool.
The cost of creating a new connection 'from scratch' is significant because the authentication requires several roundtrips between client and server (depending on the authentication method and on SSL settings it can be 1 roundtrip in best case vs. about 10 in worse).
And to answer your question, connection raise the OnStateChange event when their state changes, but you shouldn't care about this if you use the pooling.
In my recent experience if you use this code:
using(SQLConnection conn = new SQLConnection(connectionString))
{
// do stuff with conn
}
have an error, and do not explicitly close the connection, it will not be closed or checked back into the pool. So use a catch or finally block to close the connection
Related
I want to use a connection pooling in my C# project. I understand that one I get the connection to the SQL server, while I'm using the same connection string, the cash pooling will work.
However I have doubts about: how is the best practice to pass the connection string through my different classes? Should I pass the connection string as a parameter to the methods that use it to connect? (for instance each time that I need to do a query)
ADO.NET has built-in connection pooling, and you can't really build a better one.
When you create a connection using a connection string, the Framework checks the connection pool to see if a connection with that connection string is available. If one is, it pulls it from the pool and returns it to you; otherwise, it creates a new one and returns that to you.
Similarly, when you close (dispose of) a connection, it is not immediately destroyed.
When you close a connection with a specific connection string, it is not immediately destroyed. Instead, it is released back into the connection pool.
Automatic connection pooling can be disabled, so that you could roll your own solution, but it's not advisable.
EDIT:
As pointed out, I didn't answer the question in my original answer.
In general, you don't pass connection strings around. Instead, they are stored in a configuration file (either web.config or app.config), in the connectionStrings section. When you need a connection string, you retrieve it within the method that requires it using ConfigurationManager.ConnectionStrings.
I don't get what is the syntax difference between regular connection and connection pool.
When I'm using the using key such as:
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
command.ExecuteNonQuery();
}
Is this the way to perform a connection pool?
You can read about connection pooling here.
Basically, as long as the connection string is the same (including case), connections will be taken from the same connection pool.
You do not control the connection pool with connections but with the connection string. Most ADO providers use pooling per default.
The using statement is used to call the Dispose method of the object (in this case the connection class). By doing so, the connection is either returned to the pool or being disconnected depending of the connection string configuration.
You should also be aware of that connections are not returned to the pool directly if distributed transactions are being used (TransactionScope in .Net 4). The connections are returned when the transaction have been completed/rolled back.
If you are not using using, you should make sure that you call Connection.Close() as soon as possible. Especially if your application is under some form of load.
The management of connection pool is abstracted away from you using SqlConnection like in the above. By default in ADO.NET connection pool is turn on and you can further control that such as turning it off or controlling the pool size in the connection string e.g.
Turn off
Provider=SQLOLEDB;Data Source=localhost;Integrated Security=SSPI;Pooling=false;
or controlling min and max
Provider=SQLOLEDB;Data Source=localhost;Integrated Security=SSPI;Min Pool Size=5; Max Pool Size=20;
More details explanation and way to verify the pool
http://www.codeproject.com/KB/dotnet/ADONET_ConnectionPooling.aspx
as far as i know,
connection pooling is managed by ado.net client, since making connections to db is costly operation. ado.net makes pool of connections and whenever you need a connection it tries to give it from pool. even if you say to client code to close connection, ado.net hold that connection for later use. you dont manage the pooling
connection pool is told in web.config file of application. when you use using statements , you tell that object should be disposed end of using.
The SQL connection defaul is connection pooling.
(Max Pool Size=100)
You can config you connection pool from connection string.
You can find more informamtion about connection string from here.
I have a long-running .NET process (a Windows service), which talks to a SQL Server.
Originally, I opened a connection when the service started up, and just kept it open. However, occasionally a network hiccup or reboot of the SQL Server would break that connection, and my process wouldn't know this. It would attempt to keep throwing SQL against a closed connection.
Trying to maintain an open connection like that was clearly me trying to be too clever. So, do I:
Create (and open) a new SqlConnection object every time
Create the connection once on service start-up, and just attempt to re-open the connection every time
For the latter (#2), I have this code:
if(connection.State != ConnectionState.Open)
{
connection.Open();
}
I only have to do this because the connection already exists. If I created the connection fresh each time (#1), clearly it would be closed and I would need to open it.
What I'm hoping to do is take advantage of SQL connection pooling to actually not open a new connection every time, but just let the connection pool manage that -- give me an open connection when it has one, or open a new one when it doesn't.
To achieve this, does it matter if I create the connection fresh each time (#1), or if I just-reuse a connection and attempt to re-open it each time (#2)?
Connection pooling means that even if you do (1), under the hood, the framework will do (2) for you for improved performance. So you can feel free to create a new connection each time.
It's worth pointing out that, for the most part, the pooling only applies to identical connection strings. So if you change certain options, those connections may not be pooled.
I am tracing a bug in a library I did not write myself. When using this library with ASP.NET, I get db connection errors because the SQLConnection seems to get closed when a second Connection is being opened with the same connection string.
Is this documented behaviour? Can opening a new SQLConnection with the same connection string close another SQLConnection object?
From debugging that seems to be the most likely cause for my problems, but I could not find anything on the web to support my theory.
No, what will happen is that when you call the SqlConnection.Open() method, even with the same connection string parameters, it will do one of two things: either reuse an unused connection from the pool, or create a new connection. Either way, you will result in non-conflicting SPIDs for SQL Server.
Is this documented behaviour?
No.
Can opening a new SQLConnection with the same connection string close another SQLConnection object?
No.
Note that unless you've modified the settings, SQL Server permits 32,767 simultaneous connections. But even then, that would not explain the behavior that you are seeing.
In short, opening a new connection with the same connection string will not close your existing connection. However... reusing the already existing object by creating a new reference to a new connection will destroy the connection.
When opening a connection to SQL Server 2005 from our web app, we occasionally see this error:
"Impersonate Session Security Context" cannot be called in this batch because a simultaneous batch has called it.
We use MARS and connection pooling.
The exception originates from the following piece of code:
protected SqlConnection Open()
{
SqlConnection connection = new SqlConnection();
connection.ConnectionString = m_ConnectionString;
if (connection != null)
{
try
{
connection.Open();
if (m_ExecuteAsUserName != null)
{
string sql = Format("EXECUTE AS LOGIN = {0};", m_ExecuteAsUserName);
ExecuteCommand(connection, sql);
}
}
catch (Exception exception)
{
connection.Close();
connection = null;
}
}
return connection;
}
I found an MS Connect article which suggests that the error is caused when a previous command has not yet terminated before the EXECUTE AS LOGIN command is sent. Yet how can this be if the connection has only just been opened?
Could this be something to do with connection pooling interacting strangely with MARS?
UPDATE: For the short-term we have implemented a workaround by clearing out the connection pool whenever this happens, to get rid of the bad connection, as it otherwise keeps getting handed back to various users. (This now happens a 5-10 times a day with only a small number of simultaneous users, so it is fairly annoying.) But if anyone has any further ideas, we are still looking out for a real solution...
I would say it's MARS rather then pooling
From "Using Multiple Active Result Sets (MARS)"
Applications can have multiple default
result sets open and can interleave
reading from them.
Applications can
execute other statements (for example,
INSERT, UPDATE, DELETE, and stored
procedure calls) while default result
sets are open.
Connection pooling in it's basic form means the connection open/close overhead is minimised, but any connection (until MARS) has one thing going on at any one time. Pooling has been around for some time and just works out of the box.
MARS (I've not used it BTW) introduces overlapping "stuff" going on for any single connection. So it's probably MARS rather than connection pooling is the bigger culprit of the 2.
From "Extending Database Impersonation by Using EXECUTE AS"
When impersonating a principal by
using the EXECUTE AS LOGIN statement,
or within a server-scoped module by
using the EXECUTE AS clause, the scope
of the impersonation is server-wide.
This may explain why MARS is causing it: the same principal in 2 session both running EXECUTE AS.
There may be something in that article of use, or try this:
IF ORIGINAL_LOGIN() = SUSER_SNAME() EXECUTE AS LOGIN = {0};
On reflection and after reading for this answer, I've not convinced that trying to change execution context for each session (MARS) in one connections is a good idea...
Don't blame connection pooling - MARS is quite notorious for wreaking a havoc. It's not entirely it's blame but it's kind of half and half. The key thing to remember is that MARS is designed, and only works with "normal" DB use (meaning, regular CRUD stuff no admin batches). Any commands that have a wide effect on DB engine can trip MARS even if it's just one connection and single threaded (like running a setup batch to create tables or a nested transaction).
Having said that, one can easily just blame MARS, but it works perfecly fine for normal CRUD scenarios which are like 99% (and things with low efficiencey like ORM-s and LINQ depend on it for life). Meaning that it's important for people to learn that if they want to hack SQL through a connection they can't use MARS. For example I had a setup code that was creating whole DB from scratch, beceuse it's very convenient for deployment, but it was sharing connection sting with web service it was deploying - oops :-) Took me a few days of digging to learn my lesson. So I just maintain the separation of concerns (which is always good) and problems went away.
Have you tried to use a revert at the end of your sql statement?
http://msdn.microsoft.com/en-us/library/ms178632.aspx
I always do this to just make sure the current context is back to normal.