我想关闭与SQL Server的现有连接,以便我可以对该数据库执行还原。我正在使用实体框架。我试着执行
alter database YourDb
set single_user with rollback immediate
然后我得到一个例外说
连接未关闭
我无法弄清楚为什么不允许连接关闭?
此图像显示完整的异常
这是方法,
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()
答案 0 :(得分:11)
似乎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);
答案 1 :(得分:8)
当您在连接上拨打Open()
两次时,会收到该错误。您应该创建在using
块中创建的所有SqlConnection对象,并且只打开它们一次。
如果你重复使用连接"使它更快" .NET已默认通过Connection Pooling为您执行此操作,但您必须处置连接对象才能使其正常工作。
答案 2 :(得分:4)
您需要处理读卡器,命令和连接。你的读者没有被处理。此代码段将保证即使在读取过程中抛出异常,连接也会关闭。
using (var conn = new SqlConnection("..."))
{
conn.Open();
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "Command text.....";
using (var reader = cmd.ExecuteReader())
{
....
}
}
}
答案 3 :(得分:2)
您的第一个问题(现在已发布您的代码)是您打开两次电话:
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,你应该做任何你需要做的事情。记住,连接到主人!!如果你连接到数据库,你试图重置你最终关闭所有连接,包括你自己,这将无法正常工作!
将目录更改为主目录。
示例连接字符串(from MSDN):
"Persist Security Info=False;Integrated Security=true;Initial Catalog=Master;server=(local)"
还要确保您使用的SQL用户具有掌握的完全权限。您可以通过打开管理工作室并查看master下的用户集合来完成此操作。
答案 4 :(得分:2)
错误很明显......使用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
现在你可以从代码中运行这个存储过程,它甚至可以杀死你自己的开放连接。享受!
答案 5 :(得分:1)
最好在尝试打开连接之前检查连接是否打开。在尝试打开连接之前尝试添加一个检查,如下所示:
function GetSomeDeferredStuff(elem, name, cycles) {
// if no `elem`:`this` object passed , utilize empty object `{}`
var el = (elem || {})
// if no `name` passsed, utilize `String` `"q"`
, queueName = (name || "q")
// if no `cycles` how many functions passed to `.queue(queueName)`,
// pass `5` functions to `.queue(queueName)`
, len = (cycles || 5);
return $(el).queue(queueName
, $.map(Array(len), function (_, index) {
return function (next) {
return $.ajax({
type: "POST",
url: '/echo/html/',
data: {
html: "<p>Task #" + (1 + index) + " complete.",
delay: (index + 1) / 2
},
success: function (data) {
return $("div").append(data);
}
// call "next" function in `queue`
}).then(next)
}
// `.dequeue(queueName)` , return `queueName` jQuery promise object,
// when all functions in `queue(queueName)` called ;
// `.queue(queueName)` empty
})).dequeue(queueName).promise(queueName);
}
$(function () {
$("a").click(function () {
var promise = GetSomeDeferredStuff();
promise.then(function () {
// `this`:`elem` , or `{}`
$("div").append("<p>All done!</p>");
});
});
});
这有助于防止您所描述的问题。
答案 6 :(得分:0)
您可以使用SqlConnection.ClearAllPools和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();
答案 7 :(得分:0)
一旦这样检查,这是我的数据访问层样本:
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();
}
}