如何以编程方式关闭与数据库的所有现有连接
How to close all existing connections to a DB programmatically
我想关闭与 SQL 服务器的现有连接,以便我可以对该数据库进行恢复。我正在使用 entity framework。我尝试执行
alter database YourDb
set single_user with rollback immediate
但后来我得到一个例外说
Connection was not closed
我不明白为什么不允许关闭连接?
这张图片显示了完整的例外情况
这是方法,
public void dbQueueryExctr(string queuery)
{
SqlCommand cmd = new SqlCommand();
SqlDataReader reader;
using (SqlConnection connectionx = new SqlConnection(CONNECTIONSTRING))
{
connectionx.Open();
//connectionx.Open(); // Removed
cmd.CommandText = queuery;
cmd.CommandType = CommandType.Text;
cmd.Connection = connectionx;
reader = cmd.ExecuteReader();
connectionx.Close();
}
编辑:
我删除了第一个 .Open()。现在我只有 Open()
当您在一个连接上调用 Open()
两次时,您会收到该错误。您应该使在 using
块内创建的所有 SqlConnection 对象只打开一次。
如果您正在重用连接 "to make it faster" .NET 已经默认通过 Connection Pooling 为您完成此操作,但您必须处理连接对象才能使其正常工作。
你的第一个问题(现在你已经发布了你的代码)是你调用了两次打开:
public void dbQueueryExctr(string queuery)
{
SqlCommand cmd = new SqlCommand();
SqlDataReader reader;
using (SqlConnection connectionx = new SqlConnection(CONNECTIONSTRING))
{
//YOU CALL OPEN HERE
//DELETE THIS ONE!!!
connectionx.Open();
cmd.CommandText = queuery;
cmd.CommandType = CommandType.Text;
cmd.Connection = connectionx;
//AND OPEN HERE
connectionx.Open();
reader = cmd.ExecuteReader();
//You do not need connectionx.Close() here
//You have it within a using which will dispose the connection
//upon exiting the using scope.
connectionx.Close();
}
接下来您的问题将要求您重置数据库以强制关闭所有连接。您必须使用单独的连接字符串连接到 MASTER,而不是您试图关闭所有连接的数据库。
alter database <data base>
set offline with rollback immediate
alter database <data base>
set online with rollback immediate
一旦你从 MASTER 对需要重置的数据库执行了上面的 SQL,你应该做好做任何你需要做的事情。记住,连接到 master!!如果你连接到你试图重置的数据库,你最终会关闭所有连接,包括你自己,这将不起作用!
将您的目录更改为 master。
示例连接字符串 (from MSDN):
"Persist Security Info=False;Integrated Security=true;Initial Catalog=Master;server=(local)"
还要确保您正在使用的 SQL 用户拥有完全的掌握权限。您可以通过打开管理工作室并查看 master 下的用户集合来执行此操作。
错误很明显...以这种方式使用 Linq,您无法关闭当前的连接。我没有尝试过这个,但我认为以下方法可行...尝试在您的数据库中创建一个存储过程,并使用 TableAdapter 或 SqlCommand 在您的 C# 代码中 运行 它(您仍然可以使用 Linq)。您的代码不会知道您即将 运行 一个即将终止其连接的存储过程,因此它应该可以工作。
CREATE PROCEDURE [dbo].[sp_KillSpidsByDBName]
@dbname sysname = ''
AS
BEGIN
-- check the input database name
IF DATALENGTH(@dbname) = 0 OR LOWER(@dbname) = 'master' OR LOWER(@dbname) = 'msdb'
RETURN
DECLARE @sql VARCHAR(30)
DECLARE @rowCtr INT
DECLARE @killStmts TABLE (stmt VARCHAR(30))
-- find all the SPIDs for the requested db, and create KILL statements
-- for each of them in the @killStmts table variable
INSERT INTO @killStmts SELECT 'KILL ' + CONVERT (VARCHAR(25), spid)
FROM master..sysprocesses pr
INNER JOIN master..sysdatabases db
ON pr.dbid = db.dbid
WHERE db.name = @dbname
-- iterate through all the rows in @killStmts, executing each statement
SELECT @rowCtr = COUNT(1) FROM @killStmts
WHILE (@rowCtr > 0)
BEGIN
SELECT TOP(1) @sql = stmt FROM @killStmts
EXEC (@sql)
DELETE @killStmts WHERE stmt = @sql
SELECT @rowCtr = COUNT(1) FROM @killStmts
END
END
GO
现在您可以从代码中 运行 这个存储过程,它会终止打开的连接,甚至是您自己的连接。享受吧!
您可以使用 SqlConnection.ClearAllPools and SqlConnection.ClearPool 关闭来自 .NET 的所有或一个连接。
ClearPool 清除与连接关联的连接池。如果在调用时与连接关联的其他连接正在使用中,它们会被适当标记并在对它们调用 Close 时被丢弃(而不是返回到池中)。
ClearAllPools 重置(或清空)连接池。如果在调用时有连接正在使用,它们会被适当标记,并在对它们调用 Close 时被丢弃(而不是返回到池中)。
例如:
using(var comm = new SqlConnection())
using(var comExecuteInsert = new SqlCommand())
{
comExecuteInsert.Connection = comm;
comExecuteInsert.CommandType = CommandType.StoredProcedure;
comExecuteInsert.CommandText = strProcedureName;
comExecuteInsert.ExecuteScalar();
comExecuteInsert.Parameters.Clear();
comm.Close();
}
SqlConnection.ClearAllPools();
Entity Framework 似乎确实保持了与数据库的连接。您可以看到它在 SQL Server Management Studio 中执行 sp_who2
,其中 Entity Framework 在 ProgramName.
下列为 EntityFrameworkMUE
虽然您不必使用"raw" sql语句来断开活动连接,但也可以通过这种方式解决:
Server server = new Server(".\SQLEXPRESS");
Database database = new Database(server, dbName);
database.Refresh();
server.KillAllProcesses(dbName);
database.DatabaseOptions.UserAccess = DatabaseUserAccess.Single;
database.Alter(TerminationClause.RollbackTransactionsImmediately);
//restore.SqlRestore(server);
以这种方式考试后,这是我的数据访问层示例:
public T ExecuteScalar<T>(SqlCommand cmd, params SqlParameter[] Params)
{
try
{
if (Transaction != null && Transaction != default(SqlTransaction))
cmd.Transaction = Transaction;
else
cmd.Connection = SqlConn;
if (Params != null && Params.Length > 0)
{
foreach (var param in Params)
cmd.Parameters.Add(param);
}
Open();
var retVal = cmd.ExecuteScalar();
if (retVal is T)
return (T)retVal;
else if (retVal == DBNull.Value)
return default(T);
else
throw new Exception("Object returned was of the wrong type.");
}
finally
{
Close();
}
}
您需要配置reader、命令和连接。您的 reader 未处理。此代码片段将保证连接关闭,即使在读取过程中抛出异常也是如此。
using (var conn = new SqlConnection("..."))
{
conn.Open();
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "Command text.....";
using (var reader = cmd.ExecuteReader())
{
....
}
}
}
最好在尝试打开连接之前检查连接是否打开。在尝试打开连接之前尝试添加检查,如下所示:
using (SqlConnection connectionx = new SqlConnection(CONNECTIONSTRING))
{
if(connectionx.State != ConnectionState.Open
connectionx.Open();
cmd.CommandText = queuery;
cmd.CommandType = CommandType.Text;
cmd.Connection = connectionx;
reader = cmd.ExecuteReader();
connectionx.Close();
}
这将有助于防止您描述的问题。
我想关闭与 SQL 服务器的现有连接,以便我可以对该数据库进行恢复。我正在使用 entity framework。我尝试执行
alter database YourDb
set single_user with rollback immediate
但后来我得到一个例外说
Connection was not closed
我不明白为什么不允许关闭连接?
这张图片显示了完整的例外情况
这是方法,
public void dbQueueryExctr(string queuery)
{
SqlCommand cmd = new SqlCommand();
SqlDataReader reader;
using (SqlConnection connectionx = new SqlConnection(CONNECTIONSTRING))
{
connectionx.Open();
//connectionx.Open(); // Removed
cmd.CommandText = queuery;
cmd.CommandType = CommandType.Text;
cmd.Connection = connectionx;
reader = cmd.ExecuteReader();
connectionx.Close();
}
编辑: 我删除了第一个 .Open()。现在我只有 Open()
当您在一个连接上调用 Open()
两次时,您会收到该错误。您应该使在 using
块内创建的所有 SqlConnection 对象只打开一次。
如果您正在重用连接 "to make it faster" .NET 已经默认通过 Connection Pooling 为您完成此操作,但您必须处理连接对象才能使其正常工作。
你的第一个问题(现在你已经发布了你的代码)是你调用了两次打开:
public void dbQueueryExctr(string queuery)
{
SqlCommand cmd = new SqlCommand();
SqlDataReader reader;
using (SqlConnection connectionx = new SqlConnection(CONNECTIONSTRING))
{
//YOU CALL OPEN HERE
//DELETE THIS ONE!!!
connectionx.Open();
cmd.CommandText = queuery;
cmd.CommandType = CommandType.Text;
cmd.Connection = connectionx;
//AND OPEN HERE
connectionx.Open();
reader = cmd.ExecuteReader();
//You do not need connectionx.Close() here
//You have it within a using which will dispose the connection
//upon exiting the using scope.
connectionx.Close();
}
接下来您的问题将要求您重置数据库以强制关闭所有连接。您必须使用单独的连接字符串连接到 MASTER,而不是您试图关闭所有连接的数据库。
alter database <data base>
set offline with rollback immediate
alter database <data base>
set online with rollback immediate
一旦你从 MASTER 对需要重置的数据库执行了上面的 SQL,你应该做好做任何你需要做的事情。记住,连接到 master!!如果你连接到你试图重置的数据库,你最终会关闭所有连接,包括你自己,这将不起作用!
将您的目录更改为 master。
示例连接字符串 (from MSDN):
"Persist Security Info=False;Integrated Security=true;Initial Catalog=Master;server=(local)"
还要确保您正在使用的 SQL 用户拥有完全的掌握权限。您可以通过打开管理工作室并查看 master 下的用户集合来执行此操作。
错误很明显...以这种方式使用 Linq,您无法关闭当前的连接。我没有尝试过这个,但我认为以下方法可行...尝试在您的数据库中创建一个存储过程,并使用 TableAdapter 或 SqlCommand 在您的 C# 代码中 运行 它(您仍然可以使用 Linq)。您的代码不会知道您即将 运行 一个即将终止其连接的存储过程,因此它应该可以工作。
CREATE PROCEDURE [dbo].[sp_KillSpidsByDBName]
@dbname sysname = ''
AS
BEGIN
-- check the input database name
IF DATALENGTH(@dbname) = 0 OR LOWER(@dbname) = 'master' OR LOWER(@dbname) = 'msdb'
RETURN
DECLARE @sql VARCHAR(30)
DECLARE @rowCtr INT
DECLARE @killStmts TABLE (stmt VARCHAR(30))
-- find all the SPIDs for the requested db, and create KILL statements
-- for each of them in the @killStmts table variable
INSERT INTO @killStmts SELECT 'KILL ' + CONVERT (VARCHAR(25), spid)
FROM master..sysprocesses pr
INNER JOIN master..sysdatabases db
ON pr.dbid = db.dbid
WHERE db.name = @dbname
-- iterate through all the rows in @killStmts, executing each statement
SELECT @rowCtr = COUNT(1) FROM @killStmts
WHILE (@rowCtr > 0)
BEGIN
SELECT TOP(1) @sql = stmt FROM @killStmts
EXEC (@sql)
DELETE @killStmts WHERE stmt = @sql
SELECT @rowCtr = COUNT(1) FROM @killStmts
END
END
GO
现在您可以从代码中 运行 这个存储过程,它会终止打开的连接,甚至是您自己的连接。享受吧!
您可以使用 SqlConnection.ClearAllPools and SqlConnection.ClearPool 关闭来自 .NET 的所有或一个连接。
ClearPool 清除与连接关联的连接池。如果在调用时与连接关联的其他连接正在使用中,它们会被适当标记并在对它们调用 Close 时被丢弃(而不是返回到池中)。
ClearAllPools 重置(或清空)连接池。如果在调用时有连接正在使用,它们会被适当标记,并在对它们调用 Close 时被丢弃(而不是返回到池中)。
例如:
using(var comm = new SqlConnection())
using(var comExecuteInsert = new SqlCommand())
{
comExecuteInsert.Connection = comm;
comExecuteInsert.CommandType = CommandType.StoredProcedure;
comExecuteInsert.CommandText = strProcedureName;
comExecuteInsert.ExecuteScalar();
comExecuteInsert.Parameters.Clear();
comm.Close();
}
SqlConnection.ClearAllPools();
Entity Framework 似乎确实保持了与数据库的连接。您可以看到它在 SQL Server Management Studio 中执行 sp_who2
,其中 Entity Framework 在 ProgramName.
虽然您不必使用"raw" sql语句来断开活动连接,但也可以通过这种方式解决:
Server server = new Server(".\SQLEXPRESS");
Database database = new Database(server, dbName);
database.Refresh();
server.KillAllProcesses(dbName);
database.DatabaseOptions.UserAccess = DatabaseUserAccess.Single;
database.Alter(TerminationClause.RollbackTransactionsImmediately);
//restore.SqlRestore(server);
以这种方式考试后,这是我的数据访问层示例:
public T ExecuteScalar<T>(SqlCommand cmd, params SqlParameter[] Params)
{
try
{
if (Transaction != null && Transaction != default(SqlTransaction))
cmd.Transaction = Transaction;
else
cmd.Connection = SqlConn;
if (Params != null && Params.Length > 0)
{
foreach (var param in Params)
cmd.Parameters.Add(param);
}
Open();
var retVal = cmd.ExecuteScalar();
if (retVal is T)
return (T)retVal;
else if (retVal == DBNull.Value)
return default(T);
else
throw new Exception("Object returned was of the wrong type.");
}
finally
{
Close();
}
}
您需要配置reader、命令和连接。您的 reader 未处理。此代码片段将保证连接关闭,即使在读取过程中抛出异常也是如此。
using (var conn = new SqlConnection("..."))
{
conn.Open();
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "Command text.....";
using (var reader = cmd.ExecuteReader())
{
....
}
}
}
最好在尝试打开连接之前检查连接是否打开。在尝试打开连接之前尝试添加检查,如下所示:
using (SqlConnection connectionx = new SqlConnection(CONNECTIONSTRING))
{
if(connectionx.State != ConnectionState.Open
connectionx.Open();
cmd.CommandText = queuery;
cmd.CommandType = CommandType.Text;
cmd.Connection = connectionx;
reader = cmd.ExecuteReader();
connectionx.Close();
}
这将有助于防止您描述的问题。