如何以编程方式关闭与DB的所有现有连接

时间:2015-05-07 05:20:12

标签: c# sql-server database entity-framework restore

我想关闭与SQL Server的现有连接,以便我可以对该数据库执行还原。我正在使用实体框架。我试着执行

alter database YourDb 
set single_user with rollback immediate

然后我得到一个例外说

  

连接未关闭

我无法弄清楚为什么不允许连接关闭?

此图像显示完整的异常

enter image description here

这是方法,

 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()

8 个答案:

答案 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.ClearAllPoolsSqlConnection.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();
        }

    }