My web application is in asp.net 2.0,c#2.0 and sql server 208 how can i find number of open connections on my sql server 2008 database.and is there any way to clear connection pool.because my site is hosted on shared hosting and they have provided limited connections. In my codding i have closed all the connection after use, but still i am getting warning for suspending database.
Can any one tell me how to find number open connections on database and and how to clear connection pool.
i used using statements for connections and closed all connections after used in finally block. so though there is error it closes oped connections.
Thanks in advance.
This shows the number of connections per each DB:
SELECT
DB_NAME(dbid) as DBName,
COUNT(dbid) as NoOfConnections,
loginame as LoginName
FROM
sys.sysprocesses
WHERE
dbid > 0
GROUP BY
dbid, loginame
And this gives total connections:
SELECT
COUNT(dbid) as TotalConnections
FROM
sys.sysprocesses
WHERE
dbid > 0
From c#, you can follow :
http://www.c-sharpcorner.com/UploadFile/dsdaf/ConnPooling07262006093645AM/ConnPooling.aspx
Another good reference can be found at :
http://www.wduffy.co.uk/blog/monitoring-database-connections/
Call the static method ReleaseObjectPool on the the OleDbConnection - see http://msdn.microsoft.com/en-us/library/system.data.oledb.oledbconnection.releaseobjectpool.aspx
Sql query to get the current active connection
SELECT DB_NAME(dbid) as 'DbNAme', COUNT(dbid) as 'Connections' from master.dbo.sysprocesses with (nolock) WHERE dbid > 0 GROUP BY dbid
you can define dbid if you want connection specific to database
You might want to read up on connection pooling: http://msdn.microsoft.com/en-us/library/8xx3tyca.aspx
A separate connection pool is created for each distinct connect string. Further, if you are connecting via integraged security and your web site is using Basic or Windows authentication (rather than anonymous), a separate connection pool will be created for each user of the web site.
To clear connection pools, the SqlConnection object provides the methods ClearPool() and ClearAllPool()`. However, an individual connection won't be closed and removed from the pool until it is closed or disposed.
All the various objects involved in the execution of the sql query that implement IDisposable should be wrapped in a using statement to guaranteed proper disposal. Something along these lines:
IEnumerable<BusinessObject> list = new List<BusinessObject>() ;
using ( SqlConnection connection = new SqlConnection( credentials ) )
using ( SqlCommand command = connection.CreateCommand() )
using ( SqlDataAdapter adapter = new SqlDataAdapter( command ) )
using ( DataSet results = new DataSet() )
{
command.CommandType = CommandType.StoredProcedure ;
command.CommandText = #"someStoredProcedure" ;
try
{
connection.Open() ;
adapter.Fill( results ) ;
connection.Close() ;
list = TransformResults( results ) ;
}
catch
{
command.Cancel() ;
throw
}
}
return list ;
You can examine what SPIDs are open in Sql Server either by executing the stored procedure sp_who (must have the appropriate admin permissions in the SQL Server). You can also use perfmon.
Related
As demonstrated by previous Stack Overflow questions (TransactionScope and Connection Pooling and How does SqlConnection manage IsolationLevel?), the transaction isolation level leaks across pooled connections with SQL Server and ADO.NET (also System.Transactions and EF, because they build on top of ADO.NET).
This means, that the following dangerous sequence of events can happen in any application:
A request happens which requires an explicit transaction to ensure data consistency
Any other request comes in which does not use an explicit transaction because it is only doing uncritical reads. This request will now execute as serializable, potentially causing dangerous blocking and deadlocks
The question: What is the best way to prevent this scenario? Is it really required to use explicit transactions everywhere now?
Here is a self-contained repro. You will see that the third query will have inherited the Serializable level from the second query.
class Program
{
static void Main(string[] args)
{
RunTest(null);
RunTest(IsolationLevel.Serializable);
RunTest(null);
Console.ReadKey();
}
static void RunTest(IsolationLevel? isolationLevel)
{
using (var tran = isolationLevel == null ? null : new TransactionScope(0, new TransactionOptions() { IsolationLevel = isolationLevel.Value }))
using (var conn = new SqlConnection("Data Source=(local); Integrated Security=true; Initial Catalog=master;"))
{
conn.Open();
var cmd = new SqlCommand(#"
select
case transaction_isolation_level
WHEN 0 THEN 'Unspecified'
WHEN 1 THEN 'ReadUncommitted'
WHEN 2 THEN 'ReadCommitted'
WHEN 3 THEN 'RepeatableRead'
WHEN 4 THEN 'Serializable'
WHEN 5 THEN 'Snapshot'
end as lvl, ##SPID
from sys.dm_exec_sessions
where session_id = ##SPID", conn);
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine("Isolation Level = " + reader.GetValue(0) + ", SPID = " + reader.GetValue(1));
}
}
if (tran != null) tran.Complete();
}
}
}
Output:
Isolation Level = ReadCommitted, SPID = 51
Isolation Level = Serializable, SPID = 51
Isolation Level = Serializable, SPID = 51 //leaked!
The connection pool calls sp_resetconnection before recycling a connection. Resetting the transaction isolation level is not in the list of things that sp_resetconnection does. That would explain why "serializable" leaks across pooled connections.
I guess you could start each query by making sure it's at the right isolation level:
if not exists (
select *
from sys.dm_exec_sessions
where session_id = ##SPID
and transaction_isolation_level = 2
)
set transaction isolation level read committed
Another option: connections with a different connection string do not share a connection pool. So if you use another connection string for the "serializable" queries, they won't share a pool with the "read committed" queries. An easy way to alter the connection string is to use a different login. You could also add a random option like Persist Security Info=False;.
Finally, you could make sure every "serializable" query resets the isolation level before it returns. If a "serializable" query fails to complete, you could clear the connection pool to force the tainted connection out of the pool:
SqlConnection.ClearPool(yourSqlConnection);
This is potentially expensive, but failing queries are rare, so you should not have to call ClearPool() often.
In SQL Server 2014 this seem to have been fixed. If using TDS protocol 7.3 or higher.
Running on SQL Server version 12.0.2000.8 the output is:
ReadCommitted
Serializable
ReadCommitted
Unfortunately this change is not mentioned in any documentation such as:
Behavior Changes to Database Engine Features in SQL Server 2014
Breaking Changes to Database Engine Features in SQL Server 2014
But the change has been documented on a Microsoft Forum.
Update 2017-03-08
Unfortunately this was later "unfixed" in SQL Server 2014 CU6 and SQL Server 2014 SP1 CU1 since it introduced a bug:
FIX: The transaction isolation level is reset incorrectly when the SQL Server connection is released in SQL Server 2014
"Assume that you use the TransactionScope class in SQL Server client-side source code, and you do not explicitly open the SQL Server connection in a transaction. When the SQL Server connection is released, the transaction isolation level is reset incorrectly."
Workaround
It appears that, since passing through a parameter makes the driver use sp_executesql, this forces a new scope, similar to a stored procedure. The scope is rolled back after the end of the batch.
Therefore, to avoid the leak, pass through a dummy parameter, as show below.
using (var conn = new SqlConnection(connString))
using (var comm = new SqlCommand(#"
SELECT transaction_isolation_level FROM sys.dm_exec_sessions where session_id = ##SPID
", conn))
{
conn.Open();
Console.WriteLine(comm.ExecuteScalar());
}
using (var conn = new SqlConnection(connString))
using (var comm = new SqlCommand(#"
SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
SELECT transaction_isolation_level FROM sys.dm_exec_sessions where session_id = ##SPID
", conn))
{
comm.Parameters.Add("#dummy", SqlDbType.Int).Value = 0; // see with and without
conn.Open();
Console.WriteLine(comm.ExecuteScalar());
}
using (var conn = new SqlConnection(connString))
using (var comm = new SqlCommand(#"
SELECT transaction_isolation_level FROM sys.dm_exec_sessions where session_id = ##SPID
", conn))
{
conn.Open();
Console.WriteLine(comm.ExecuteScalar());
}
For those using EF in .NET, you can fix this for your whole application by setting a different appname per isolation level (as also stated by #Andomar):
//prevent isolationlevel leaks
//https://stackoverflow.com/questions/9851415/sql-server-isolation-level-leaks-across-pooled-connections
public static DataContext CreateContext()
{
string isolationlevel = Transaction.Current?.IsolationLevel.ToString();
string connectionString = ConfigurationManager.ConnectionStrings["yourconnection"].ConnectionString;
connectionString = Regex.Replace(connectionString, "APP=([^;]+)", "App=$1-" + isolationlevel, RegexOptions.IgnoreCase);
return new DataContext(connectionString);
}
Strange this is still an issue 8 years later ...
I just asked a question on this topic and added a piece of C# code, which can help around this problem (meaning: change isolation level only for one transaction).
Change isolation level in individual ADO.NET transactions only
It is basically a class to be wrapped in an 'using' block, which queries the original isolation level before and restores it later.
It does, however, require two additional round trips to the DB to check and restore the default isolation level, and I am not absolutely sure that it will never leak the altered isolation level, although I see very little danger of that.
I want to run this query in C#
SELECT *
FROM [FirstDataBase].[dbo].[table1]
INNER JOIN [SecondDataBase].[dbo].[table2]
and my code is :
SqlConnection cn = new SqlConnection(myConnectionString);
SqlCommand cmd = new SqlCommand(#"SELECT * FROM [FirstDataBase].[dbo].[table1]
INNER JOIN [SecondDataBase].[dbo].[table2]");
cmd.Connection = cn; // here is my question !!!
cn.Open();
int x = (int)cmd.ExecuteScalar();
but my query needs two connection string ... one for [FirstDataBase] and second
for [SecondDataBase]...
How can I do this ?
How can I insert two SqlConnection or ConnectionString to one SqlCommand ? or
How can I do it in other ways ?
I've actually reread your question, you don't need two connection strings. Your query command can affect any database you wish, once you've connected. For instance:
string query = #"SELECT * FROM [FirstDataBase].[dbo].[table1]
INNER JOIN [SecondDataBase].[dbo].[table2]";
using(SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionString[#"db"].ConnectionString))
using(SqlCommand command = new SqlCommand(query, connection))
{
// Logic
}
That would impact both databases should your query impact both of them. Your able to use the same hierarchy that is present in SQL Management Studio to perform your task.
You only need to connect to the first database. The query will then connect from there to the second database. Alternatively you can connect to just the second database if you prefer but the key point is that you only require one connection.
The same principle applies if you are using Management Studio, you would connect to the first database and then run the query joining across to the second.
Obviously this assumes that the first database can communicate with the second (as #Tim Medora pointed out in the comments).
If the databases are on different servers you can create a "Linked Server" in Management Studio.
From within your main database goto Server Objects -> Linked Servers.
Right-click on Linked Servers then hit "New Linked Server"
On the General page select the Type of Server you'd like to link to and enter credentials if needed.
Add the local user that will have access to the linked database and enter the "remote" user that you want to be and press Ok.
Done.
Then in front of the database name you need to specify which server. An example:
select * from [2.2.2.2].[Test].[dbo].[MyTable]
join [1.1.1.1].[OtherDb].[dbo].[OtherTable] on ...etc
The great part about Linked Servers is that you map the user so that the same user doesn't have to exist on both machines. The database with the link then automatically logs you in the the other one.
Your query is database specified "[FirstDataBase].[dbo].[table1]". So you just to connect to a database (even can be a database other that [FirstDataBase] or [SecondDataBase]). Your code should works well.
In my C# application, I do the following:
using (SqlConnection connection = new SqlConnection(connectionstr))
{
connection.Open();
SqlCommand com1 = new SqlCommand("insert into Anfangstierbestand(bestand, jahr, loginid) VALUES (" + bestand + ", " + jahr + ", " + loginid + ");", connection);
SqlCommand com2 = new SqlCommand("select * from Anfangstierbestand;", connection);
com1.Connection = connection;
int ferksum = 0;
com1.ExecuteNonQuery();
connection.Close();
connection.Open();
SqlDataReader read = com2.ExecuteReader();
while (read.Read())
{
ferksum += Convert.ToInt32(read[2]);
}
// MessageBox.Show("Fehler beim Erstellen des Tierbestandes", "Fehler"); }
MessageBox.Show(ferksum.ToString());
}
It's a simple insert to a database. I added com2 to check, if the insert works.
Unfortunately, the the value of com2 tells me, that it works, but when I go to the Server Explorer and press Execute SQL, there are no new values.
I don´t know the reason. The code above is just an example, since a few days, no insert works anymore(before, the same code works).
Does anybody know what the reason can be?
EDIT:
C#:
string connectionstr = "Data Source=.\\SQLEXPRESS;" + "AttachDbFilename=|DataDirectory|\\Datenbank\\FarmersCalc.mdf;" + "Integrated Security=True;" + "User Instance=true;";
EDIT2:
Server Explorer:
Data Source=.\SQLEXPRESS;AttachDbFilename="C:\Users\user\Desktop\Farmer´s Calc\Programmierung\WPF\Finanz_WPF\Finanz_WPF\Datenbank\FarmersCalc.mdf";Integrated Security=True;User Instance=True
EDIT3:
Here are the columns:
id int,
jahr int,
anzahl int,
loginid int
EDIT4:
Is it possible that it´s a problem that I opened my project with expression blend? Normally, I work with VS 2010...
EDIT5:
Even because I can not answer my question(<100 reputations) I write it here:
Shame on me. Some of you were right, it was the wrong database-file. But I´m still wondering, why this happened, because I did not change anything since a few days and before this, it worked!
Thanks to all for helping!
You're using user instances, why? Isn't it possible that the instance you're connecting to in Server Explorer is not the same as the instance where your app is inserting data? What happens when you select data from within the app, does it reflect your insert(s)? It seems to me based on your connection strings that these are two completely different MDF files - they have the same name but they are in different locations.
Is the issue implicit transactions? Do you need to issue a commit of the SQL Insert? If com2 tells you that it's there then it may only see it since it's in the context of the current SQL transaction.
You should share your connection string for both Server Explorer and your SqlConnection (connectionstr). Ensure that you setup your Server Explorer connection with User Instance=true;.
As a diagnostic,
connection.Open();
int n = com1.ExecuteNonQuery();
// log or show 'n' , the nr of rows affected
Edit, after seeing the connectionstrings:
local db files in |DataDirectory|\ are very prone to be overwritten by the next run or build command.
Make sure you set them to 'copy never' or 'copy if newer' in the VS Solution explorer.
Perhaps somewhere in the callstack above this code, someone has added a TransactionScope.
This would cause the connections to enroll automatically in the transaction, and the connections could see the data inserted via that not-yet-committed transaction. When the scope is exitted without calling scope.Complete, the transaction gets rolled back and no data is saved.
I can connect to MySQL database from my WinForms app fine. The question is once I am logged in how can I perform multiple select statements without having to login again?
MySqlConnection connection = new MySqlConnection(MyConString);
connection.Open();
MySqlCommand command = connection.CreateCommand();
MySqlDataReader Reader;
command.CommandText = "select id from user ";
Then I want to perform a select statement for another table without having to create connection again.
How do I dothis?
I can't seem to just do connection.CreateCommand.
As long as the queries are within the same block, you can use the same connection.. However, once closed, you need to re-open it.
using( YourConnectionObject )
{
... open connection ...
... create your sql querying object... and command
SQLCommand.Connection = YourConnectionObject;
Execute your Query
SQLCommand.CommandText = "a new sql-select statement";
Execute your NEW query while connection still open/active
SQLCommand.CommandText = "a third sql-select statement";
Execute your THIRD query while connection still open/active
... close your connection
}
However, in your application, you can have a single "connection" object like at the application level, or at a form level with the necessary login / connection settings stuff. Then, internally to each form, you can
Open
Run Query
Run Query
Run Query
Close
as needed.
I see you're using a DataReader. You can only have 1 DataReader open at a time per connection. using blocks come in handy for those:
using( var reader = myCommand.ExecuteReader() ) {
while (reader.Read()) {
// get values, do stuff
}
}// reader gets closed
You only hint at it in the code in your question (currently), but it's possible that is part of your problem. You haven't shown how you're using the DataReader, so I'm not certain. Just a possibility.
I am having problems with SQL Server dropping a connection after I have dropped and re-created a given database and the next time I try to execute a command against a new connection on that same database, I get:
A transport-level error has occurred when sending the request to the server. (provider: Shared Memory Provider, error: 0 - No process is on the other end of the pipe.)
Here is the TCP version (If I try connecting to another server)
A transport-level error has occurred when sending the request to the server. (provider: TCP Provider, error: 0 - An existing connection was forcibly closed by the remote host.)
Here are the steps to repro the problem:
Open a connection to a database and execute a sql command
Drop the database
Re-Create the database
Open a new connection to the same database and attempt to run a command against it
Result: I receive an exception
Here is the Code:
using (var conn = new System.Data.SqlClient.SqlConnection("Data Source=.;Initial Catalog=DBNAME;Integrated Security=True"))
{
conn.Open();
var cmd = conn.CreateCommand();
cmd.CommandText = "UPDATE ...";
cmd.ExecuteNonQuery();
}
string sql = "Alter Database DBNAME set single_user with rollback immediate drop database DBNAME";
var server = new Microsoft.SqlServer.Management.Smo.Server(".");
server.ConnectionContext.ExecuteNonQuery(sql);
server.ConnectionContext.Disconnect();
sql = File.ReadAllText("PathToDotSqlFile..."));
server = new Microsoft.SqlServer.Management.Smo.Server(".");
server.ConnectionContext.ExecuteNonQuery(sql);
server.ConnectionContext.Disconnect();
using (var conn = new System.Data.SqlClient.SqlConnection("Data Source=.;Initial Catalog=WER_CONFIG;Integrated Security=True"))
{
conn.Open();
var cmd = conn.CreateCommand();
cmd.CommandText = "UPDATE ...";
cmd.ExecuteNonQuery();
}
The error occurs on the line 'cmd.ExecuteNonQuery()' at the very end. It appears that even though I am creating a new connection each time I connect, sql server is keeping track of something (or possibly the ADO.net code) where the next time I ask for a connection, it gives me one that is already used or has been closed on the server side. It doesn't realize it was closed by the server (presumably because of the database it is connected to being dropped) until you try to execute another command against it.
Note that if I don't do the first step of executing the initial query, and I just drop the database, re-create it, and execute a command, I do not receive this error. I think establishing that initial connection before the database is dropped is an important part of this error.
I have also tried using an external process to drop and recreate the database like so:
ProcessStartInfo info = new ProcessStartInfo("sqlcmd.exe", " -e -E -S . -Q \"Alter Database DBNAME set single_user with rollback immediate drop database DBNAME\"");
var p = Process.Start(info);
p.WaitForExit();
info = new ProcessStartInfo("sqlcmd.exe", " -i " + PathToDotSqlFile);
p = Process.Start(info);
p.WaitForExit();
And that did not help.
Is there a way to create a new SqlConnection and ensure it is clean and not from a pool? Any other suggestions on how to solve this problem?
UPDATE: Using SqlConnection.ClearPool() did solve the problem but I chose to just edit my connection string with pooling=false which also worked.
ADO.NET automatically manages a connection pool. When you "close" a connection in your application, it is returned to the pool and kept alive, in case you request a connection with the same connection string. This could be the reason why your "new" connection is stale.
You could try to turn off this behaviour by adding pooling=false as parameter to your connection string.
Don't know about SQL2008, but this sounds like a connection pooling problem on the application side. In the old days, we added "OLEDB Services=-1" to the connection string to turn off connection pooling. There is probably a more elegant way to do this now.
edit: ADO.Net 2.0 seems to have added a ClearPool function to the SQLConnection object. (http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.clearpool(VS.80).aspx) I am very interested to know if this works.