无法恢复SQL数据库,无法获得独占访问权限(单用户模式)

本文关键字:权限 单用户 用户 模式 访问权 数据库 SQL 恢复 访问 | 更新日期: 2023-09-27 18:04:50

我正在为一个应用程序编写一个简单的数据库备份和恢复例程。我可以备份我的数据库没有问题,但是,当我恢复是我无法获得对我的数据库的独占访问权。

我正在尝试在SO上修复的所有组合,将其置于单用户模式,将其离线,然后将其放回只有没有成功。我可以在studio manager (express)中成功恢复数据库

这个方法是唯一的连接到SQL服务器,所以我不明白为什么我不能执行恢复。

感谢帮助指出问题可能在哪里。

internal void RestoreDatabase(string databaseFile)
        {
            //get database details
            var databaseConfiguration = new DatabaseConfiguration().GetDatabaseConfiguration();
            try
            {
                //construct server connection string
                var connection = databaseConfiguration.IsSqlAuthentication
                                     ? new ServerConnection(databaseConfiguration.ServerInstance,
                                                            databaseConfiguration.SqlUsername,
                                                            databaseConfiguration.SqlPassword)
                                     : new ServerConnection(databaseConfiguration.ServerInstance);
                //set database to single user and kick everyone off
                using (
                    var sqlconnection =
                        new SqlConnection(new DatabaseConfiguration().MakeConnectionString(databaseConfiguration)))
                {
                    sqlconnection.Open();
                    using (
                        var sqlcommand = new SqlCommand("ALTER DATABASE " + databaseConfiguration.DatabaseName + " SET Single_User WITH Rollback IMMEDIATE",
                                                        sqlconnection))
                    {                       
                        sqlcommand.ExecuteNonQuery();                        
                    }
                    using (
                        var sqlcommand = new SqlCommand("ALTER DATABASE " + databaseConfiguration.DatabaseName + " SET OFFLINE",
                                                        sqlconnection))
                    {
                        sqlcommand.ExecuteNonQuery();
                    }
                    using (
                        var sqlcommand = new SqlCommand("ALTER DATABASE  " + databaseConfiguration.DatabaseName + "  SET ONLINE",
                                                        sqlconnection))
                    {
                        sqlcommand.ExecuteNonQuery();
                    }
                    sqlconnection.Close();
                }
                //setup server connection and restore
                var server = new Server(connection);
                var restore = new Restore();
                restore.Database = databaseConfiguration.DatabaseName;
                restore.Action = RestoreActionType.Database;
                restore.Devices.AddDevice(databaseFile, DeviceType.File);
                restore.ReplaceDatabase = true;
                restore.Complete += Restore_Complete;
                restore.SqlRestore(server);
            }
            catch (Exception ex)
            {
                //my bad
                restoreDatabaseServerError(ex.InnerException.Message, EventArgs.Empty);
            }
            finally
            {
                //set database to multi user
                using (
                    var sqlconnection =
                        new SqlConnection(new DatabaseConfiguration().MakeConnectionString(databaseConfiguration)))
                {
                    sqlconnection.Open();
                    using (
                        var sqlcommand = new SqlCommand("ALTER DATABASE " + databaseConfiguration.DatabaseName + " SET Multi_User",
                                                        sqlconnection))
                    {
                        sqlcommand.ExecuteNonQuery();
                        sqlcommand.Dispose();
                    }
                    sqlconnection.Close();
                }
            }
        }

无法恢复SQL数据库,无法获得独占访问权限(单用户模式)

如果有人连接到你的数据库,SQL Server不能删除它,所以你必须断开现有的连接,正如你已经尝试过的。single_user的问题是,它仍然允许单个用户连接。因为你自己不能连接到数据库时,放弃它,你必须离开那里。这为其他人打开了一个连接槽,从而防止你掉下它。

有一些SQL Server进程特别擅长在那一瞬间连接到数据库。复制就是一个例子。(你不应该真的删除一个已经发布的数据库,但那是另一回事。)

那么我们能做些什么呢?唯一100%安全的方法是阻止用户连接到数据库。唯一实用的方法是将数据库离线切换,然后删除它。然而,这有一个讨厌的副作用,SQL Server不删除该数据库的文件,所以你必须手动做。

另一个选择是足够快。在您的示例中,您在删除数据库之前将其重新联机。这是一个相当资源密集的过程,给了"入侵者"大量的时间来连接。

我一直在使用的成功的解决方案是这样的:

ALTER DATABASE MyDb SET RESTRICTED_USER WITH ROLLBACK IMMEDIATE;
USE MyDb;
ALTER DATABASE MyDb SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
USE tempdb;
DROP DATABASE MyDb;

这首先将数据库设置为受限用户并连接到它。然后,在仍然连接时,它将数据库设置为单用户。之后,上下文切换到tempdb,然后立即执行删除操作。重要的是,将这些命令作为一个批量发送到SQL Server,以最大限度地减少USE tempdb;DROP之间的时间。在开始时将数据库设置为限制用户会捕获一些罕见的边缘情况,所以即使乍一看没有意义,也要保留它。

虽然这仍然为其他人留下了理论上的空白,但我从未见过它失败。

删除数据库后,您可以正常运行还原。

好运。

您的恢复需要在将DB服务器设置为单用户模式的同一连接上进行。

总结下面的更改,我将使用的结束移到还原代码的下面,并将SQL连接的关闭移到还原之后,因此它使用相同的连接。还删除了离线和在线设置,因为它们不需要。目前无法测试,所以请告诉我它是否有效。

  //set database to single user and kick everyone off
  using (var sqlconnection = new SqlConnection(new DatabaseConfiguration().MakeConnectionString(databaseConfiguration)))
  {
    sqlconnection.Open();
    using (var sqlcommand = new SqlCommand("ALTER DATABASE " + databaseConfiguration.DatabaseName + " SET Single_User WITH Rollback IMMEDIATE",sqlconnection))
    {
        sqlcommand.ExecuteNonQuery();                        
    }
    //setup server connection and restore
    var server = new Server(sqlconnection);
    var restore = new Restore();
    restore.Database = databaseConfiguration.DatabaseName;
    restore.Action = RestoreActionType.Database;
    restore.Devices.AddDevice(databaseFile, DeviceType.File);
    restore.ReplaceDatabase = true;
    restore.Complete += Restore_Complete;
    restore.SqlRestore(server);
    sqlconnection.Close();
  }
相关文章: