<p>SQL Server 备份还原需用 SqlCommand 执行 T-SQL 语句,而非 C# 封装方法;必须校验数据库名、使用服务端可写绝对路径、设置足够 CommandTimeout、处理单用户模式及权限,并避免直接复制 MDF 文件。</p>

SQL Server 备份用 BACKUP DATABASE,C# 里得走 SqlCommand
不是调某个 C# 封装好的“备份方法”,而是拼 SQL 语句交给 SQL Server 自己执行。SQL Server 的备份机制不依赖客户端,C# 只负责发命令、等结果、捕获异常。
常见错误是试图用 File.Copy 直接复制 .mdf 文件——这在数据库在线时几乎必失败,会报 数据库正在使用中 或文件被占用。
- 必须确保连接账户有
db_backupoperator(备份)或sysadmin(还原)权限 - 备份路径必须是 SQL Server 进程能访问的路径,不是你本地 C# 程序的“当前目录”——比如写
C:\backup\,得确认 SQL Server 服务账户对该目录有写权限 - 语句里不能用变量拼接数据库名或路径,必须用参数化方式防注入,但
BACKUP不支持参数化路径,所以得手动校验字符串(如白名单检查数据库名是否只含字母数字)
string sql = "BACKUP DATABASE [@dbName] TO DISK = @backupPath WITH INIT, FORMAT"; // ❌ 错误:@dbName 不会被替换
string sql = $"BACKUP DATABASE [{dbName}] TO DISK = '{backupPath}' WITH INIT, FORMAT"; // ✅ 正确:dbName 已校验,backupPath 是服务端可写绝对路径还原前必须把数据库设为 SINGLE_USER 并踢掉现有连接
直接执行 RESTORE DATABASE 十有八九报错:因为数据库正在使用中 或 无法获得对数据库的独占访问权。SQL Server 还原要求数据库完全离线,而 C# 默认连接不会自动释放其他会话。
- 先执行
ALTER DATABASE [@dbName] SET SINGLE_USER WITH ROLLBACK IMMEDIATE强制断开所有连接 - 再执行
RESTORE DATABASE,注意要指定WITH REPLACE覆盖现有数据库 - 还原成功后,别忘了
ALTER DATABASE [@dbName] SET MULTI_USER,否则应用连不上 - 如果还原目标库名和备份时不同,还得加
WITH MOVE明确数据/日志文件的新位置,否则可能报逻辑文件名不匹配
string restoreSql = $@"
ALTER DATABASE [{dbName}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
RESTORE DATABASE [{dbName}] FROM DISK = '{backupPath}'
WITH REPLACE, RECOVERY,
MOVE '{logicalDataName}' TO '{newDataPath}',
MOVE '{logicalLogName}' TO '{newLogPath}';
ALTER DATABASE [{dbName}] SET MULTI_USER;";
SqlConnection 执行长时间备份/还原会超时,必须调大 CommandTimeout
默认 30 秒超时,但一个几 GB 的数据库备份可能要几分钟。不改超时时间,ExecuteNonQuery() 直接抛 SqlException: 执行超时已过期,且数据库状态可能卡在中间(比如备份写了一半中断)。
-
SqlCommand.CommandTimeout单位是秒,建议按预估时间 ×2 设置,比如预计 5 分钟就设 600 - 不要在 UI 线程同步执行,否则界面假死;用
await cmd.ExecuteNonQueryAsync()配合 async/await - 执行期间 SQL Server 日志里会出现
Backup/Restore is running类似信息,可通过SELECT * FROM sys.dm_exec_requests WHERE command LIKE '%BACKUP%'查看进度
备份文件路径必须用 SQL Server 视角,不是 C# 程序视角
很多人写 "./backup/mydb.bak" 或 Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "backup"),结果备份文件根本没生成,也不报错——因为 SQL Server 根本没往你程序目录写,它用自己的工作目录(通常是 BINN 文件夹),或者更大概率是权限不足静默失败。
- 路径必须是 SQL Server 服务账户能读写的**绝对路径**,例如
D:\SQLBackups\mydb_2024.bak - 提前用 Windows 探索器手动建好目录,并给 SQL Server 服务账户(如
NT Service\MSSQLSERVER)赋予“修改”权限 - 可以用
SELECT SERVERPROPERTY('InstanceDefaultDataPath')查实例默认路径作参考,但别直接拿来备份 - 还原时同理:路径必须是 SQL Server 能访问的,不是你 C# 程序“看到”的路径
最麻烦的其实是权限和路径错位,不是语法。很多问题查日志才发现 SQL Server 根本没写进那个文件夹,只是安静地失败了。


















