You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

手动删除.bak后SQL Server数据库卸载重装异常问题咨询

问题背景

我们有一个通过C#在Microsoft SQL Server 2012中安装2个数据库的程序,卸载时数据库未被删除;重装时程序会检查并删除现有数据库后重建,.bak文件存储在C:/Program Files或对应目录。若卸载后手动删除.bak文件,首次重装失败,但尝试三次后可成功创建数据库。

相关C#代码:

String path = System.Reflection.Assembly.GetExecutingAssembly().Location; 
path = System.IO.Path.GetDirectoryName(path); 
Server server = InitializeServer(log); 
server.ConnectionContext.Connect(); 
Database db = server.Databases["ADB"]; 
if (db != null) { 
    try { 
        db.Drop();//-------------------------First try fails here 
    } catch (Exception ex) { 
        throw new ApplicationException(ex.Message); 
    } 
} 
try //----------------- second try database ADB gets created 
{ 
    Restore restore = new Restore(); 
    // Set type of backup to be performed to database 
    restore.Database = "ADB"; 
    restore.Action = RestoreActionType.Database; 
    restore.ReplaceDatabase = true; 
    // Create the Restore database ldf & mdf file name 
    String dataFileLocation = path + "ADB" + ".mdf"; 
    String logFileLocation = path + "ADB" + "_Log.ldf"; 
    RelocateFile rf = new RelocateFile("ADB", dataFileLocation); 
    // Set up the backup device to use filesystem. 
    restore.Devices.AddDevice(path + "\\ADB.bak", DeviceType.File); 
    System.Data.DataTable logicalRestoreFiles = restore.ReadFileList(server); 
    restore.RelocateFiles.Add(new RelocateFile(logicalRestoreFiles.Rows[0][0].ToString(), dataFileLocation)); 
    restore.RelocateFiles.Add(new RelocateFile(logicalRestoreFiles.Rows[1][0].ToString(), logFileLocation)); 
    restore.NoRecovery = false; 
    restore.SqlRestore(server); 
} catch (Exception ex) { 
    throw new ApplicationException(ex.Message); 
} 
// Installing 2nd database---------------------------------------------- 
server.ConnectionContext.Connect(); 
Database db1 = server.Databases["BDB"]; 
if (db1 != null) { 
    try { 
        db1.Drop();//-------------------------Second try fails here 
    } catch (Exception ex) { 
        throw new ApplicationException(ex.Message); 
    } 
} 
try //----------------- Third try database BDB gets created 
{ 
    Restore restore2 = new Restore(); 
    restore2.Database = "BDB"; 
    restore2.Action = RestoreActionType.Database; 
    restore2.ReplaceDatabase = true; 
    String dataFileLocation = path + "BDB" + ".mdf"; 
    String logFileLocation = path + "BDB" + "_Log.ldf"; 
    RelocateFile rf = new RelocateFile("BDB", dataFileLocation); 
    restore2.Devices.AddDevice(path + "\\BDB.bak", DeviceType.File); 
    System.Data.DataTable logicalRestoreFiles = restore2.ReadFileList(server); 
    restore2.RelocateFiles.Add(new RelocateFile(logicalRestoreFiles.Rows[0][0].ToString(), dataFileLocation)); 
    restore2.RelocateFiles.Add(new RelocateFile(logicalRestoreFiles.Rows[1][0].ToString(), logFileLocation)); 
    restore2.NoRecovery = false; 
    restore2.SqlRestore(server); 
}

删除数据库时的报错信息:

Microsoft.SqlServer.Management.Smo.FailedOperationException: Drop failed for Database 'ADB'. ---> Microsoft.SqlServer.Management.Common.ExecutionFailureException: An exception occurred while executing a Transact-SQL statement or batch. ---> System.Data.SqlClient.SqlException: Cannot drop the database 'ADB', because it does not exist or you do not have permission. 
at Microsoft.SqlServer.Management.Common.ConnectionManager.ExecuteTSql(ExecuteTSqlAction action, Object execObject, DataSet fillDataSet, Boolean catchException) 
at Microsoft.SqlServer.Management.Common.ServerConnection.ExecuteNonQuery(String sqlCommand, ExecutionTypes executionType) 
--- End of inner exception stack trace --- 
at Microsoft.SqlServer.Management.Common.ServerConnection.ExecuteNonQuery(String sqlCommand, ExecutionTypes executionType) 
at Microsoft.SqlServer.Management.Common.ServerConnection.ExecuteNonQuery(StringCollection sqlCommands, ExecutionTypes executionType) 
at Microsoft.SqlServer.Management.Smo.ExecutionManager.ExecuteNonQuery(StringCollection queries) 
at Microsoft.SqlServer.Management.Smo.SqlSmoObject.ExecuteNonQuery(StringCollection queries, Boolean includeDbContext) 
at Microsoft.SqlServer.Management.Smo.SqlSmoObject.DropImplWorker(Urn& urn) 
at Microsoft.SqlServer.Management.Smo.SqlSmoObject.DropImpl() 
--- End of inner exception stack trace --- 
at Microsoft.SqlServer.Management.Smo.SqlSmoObject.DropImpl() 
at SetupScripts.SetupDataBase.Execute(FrmLog log)

解答

1. 手动删除.bak文件后能否分离服务器数据库?

完全可以。.bak文件只是数据库的备份文件,它和SQL Server实例中存在的数据库是完全独立的两个实体。分离数据库是SQL Server对实例内数据库的管理操作,核心是把数据库从SQL Server的元数据列表中移除,但保留数据库的.mdf和.ldf物理文件,只要满足以下条件就能执行:

  • 数据库当前没有被用户或进程占用
  • 你拥有执行分离操作的权限
  • 数据库确实存在于SQL Server实例中

这个操作和.bak文件是否存在没有任何关联,你遇到的删除数据库报错,本质是程序读取的元数据和实际数据库状态不一致,和备份文件无关。

2. 为何第二次尝试能成功创建数据库?

结合你的代码和报错信息,核心原因是SQL Server SMO的元数据缓存问题,加上重试过程中程序自动恢复了.bak文件,具体拆解:

  • 首次重装失败的原因:
    代码通过server.Databases["ADB"]检查数据库是否存在时,SMO可能使用了缓存的元数据,误以为数据库还存在(但实际上卸载后数据库可能已被隐性删除,或者权限问题导致SMO读取了错误状态)。当执行db.Drop()时,SQL Server实际执行DROP DATABASE语句,发现数据库根本不存在,于是抛出Cannot drop the database 'ADB'...的错误,导致首次流程终止。
  • 第二次尝试成功的原因:
    重试时SMO的元数据缓存已经更新,此时server.Databases["ADB"]会返回null,代码直接跳过Drop()逻辑,进入数据库恢复流程。同时,你的重装程序在重试过程中应该已经重新将.bak文件复制到了指定路径,所以Restore操作能正常读取备份文件,成功创建数据库。

另外,建议优化代码:在Drop()的catch块中判断异常类型,如果是“数据库不存在”的预期错误,可以直接跳过Drop()步骤继续执行Restore,这样能避免首次重试的失败。


内容的提问来源于stack exchange,提问作者Madz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:58:19