无法恢复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 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();
}