【问题标题】:PowerShell - Nesting Try/Catch/Finally CommandsPowerShell - 嵌套 Try/Catch/Final 命令
【发布时间】:2015-12-07 23:40:21
【问题描述】:

我正在尝试编写一段代码,以使用一些 Invoke-Sqlcmd 命令(由我们的系统中的错误引起)在 PowerShell 中删除和重新创建 MS SQL 数据库。我想为此建立一些应急措施,以防目标机器上的另一个程序在发出 drop 命令时正在访问数据库。我认为这样做的一个好方法是将一个 Try/Catch/Finally 命令嵌套在另一个命令中,就像这样;

$strDbName= database
$strUsername= user
$strPassword= pass
$strmdfFilePath= "C:\foo.mdf"
$strldfFilePath= "C:\bar.ldf"

Try
    {
    Write-Host "INFO: Attempting Database DROP command..."
    Invoke-SqlCmd -Username "$strUserName" -Password "$strPassword" -Query "DROP database [$strDbName];"
    }
Catch
    {
    Try
        {
        Invoke-SqlCmd -Username "$strUserName" -Password "$strPassword" -Query "ALTER database [$strDbName] set offline with ROLLBACK IMMEDIATE;"
        Invoke-SqlCmd -Username "$strUserName" -Password "$strPassword" -Query "DROP database [$strDbName];"
    }
    Catch
        {
        Write-Host "Error message"
        }
    Finally
        {
        Exit
        }
    }
Finally
    {
    Invoke-SqlCmd -Username "$strUserName" -Password "$strPassword" -Query "CREATE DATABASE [$strDbName] ON (FILENAME = '$dirMdfFilePath'),(FILENAME = '$dirLdfFilePath') for ATTACH;"
    }

两个问题 - A) 嵌套 Try/Catch/Finally 命令真的有效吗? B) 这种类型的命令序列是好的做法吗?我没有测试机器来尝试这个,如果有更简单的方法来执行这样的命令,我想知道。

【问题讨论】:

  • 你绝对可以嵌套它们。在您的情况下,我想知道您是否可以通过事先检查表格的状态来避免它(我根本不知道该怎么做。)。那个alter命令......为什么不首先将其设置为离线?
  • 嗨,马特,我确实对此进行了调查,可以通过查询数据库中的开放连接来实现。我提出的方法绝对不是做我想做的最优雅的方式,所以我可能会研究这个在程序中实施一些防御性编码的课程。
  • 只是为了跟进这一点,我找到了以下信息;如果将变量设置为 Microsoft.SqlServer.Management.Smo.Server,则可以使用“GetActiveDBConnectionsCount("foobar")”方法输出当前特定数据库的连接数。
  • @Fredulom 将数据库设置为offline 状态可能会相当缓慢且占用大量资源。我认为更好的选择是使用set single_user,断开其他所有人的连接并回滚任何未提交的事务(= 一样安全,但速度更快)。不过仍然会立即回滚

标签: powershell powershell-2.0


【解决方案1】:

A) 嵌套的 try/catch 可以工作。这个简化的代码证明了这一点(并将帮助您在任何 Windows 中进行测试):

Write-Host "0"
Try
{
    Write-Host "1"
    throw
}
Catch
{
    Try
    {
        Write-Host "2"
        throw
    }
    Catch
    {
        Write-Host "3"
    }
    Finally
    {
        Write-Host "4"
        Exit
    }
}
Finally
{
    Write-Host "5"
}

B) 但这不是一个好习惯。您的错误处理代码(在 catch/finally 中)代码应该是健壮的、易于阅读的并且不做复杂的事情。只需将错误消息吐出以帮助调试并可能关闭一些资源。

但是,这有待商榷...查看此 SO question

【讨论】:

  • 我希望这样做的原因是我的目的是将此脚本提供给我们的支持分析师链,因此易用性和自动化是我的首要任务。由于他们缺乏诊断 SQL 问题的经验,我希望代码尝试处理这个问题。我将研究 Matt 在上面检查数据库中打开连接的方法。
  • 我注意到在内部catch 中设置Break 仍然执行最后一个子句而不是终止脚本。 (不过,我只测试了内部 trycatcher 缺少终结的情况。)这是否要求 每个 trycatcher 有一个终结语句(如果有的话)? (另外,我确实同意嵌套的 try catch 是一种糟糕的代码设计,所以我的问题是相当学术的,而不是实用的。)
猜你喜欢
  • 1970-01-01
  • 2016-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-15
  • 2019-11-12
  • 1970-01-01
相关资源
最近更新 更多