繁体   English   中英

PowerShell - 如果所有 Invoke-SQL 命令都成功,如何提交 Scope

[英]PowerShell - How to Commit Scope if all Invoke-SQL Commands are successful

我正在使用 PowerShell 版本 5,并且我正在 PowerShell 脚本中执行几个 SQL 命令。 与 SQL 服务器不同,我们在BEGIN TRANSACTIONCOMMIT TRANSACTION中执行命令,因此如果单个命令失败,所有内容都会回滚,我想在我的 Powershell 脚本中实现类似的事情。

因此,在我的场景中,如果有 3 个 SQL 命令失败,则不应删除该表:

  • 第一个删除表(如果存在)
  • 第二次创建表
  • 第三次插入记录

在插入记录时,我尝试使用数组插入多行并测试scope的工作,所以我故意添加重复的 Id 值,因此预期结果是如果 Id 即第一个数组元素有效,则继续下一个元素,但如果第二个数组元素无效,然后回滚更改。

但是由于我对 Powershell 的了解有限,因此不确定如何实现这一点,因此即使 ID 不重复或不重复,session 也不会被提交。

到目前为止,以下是我的脚本:

$connString = "Data Source=<Server-Name>;Database=<DB-Name>;User ID=<Login>;Password=<Pass>"
 
 
  $conn = New-Object System.Data.SqlClient.SqlConnection $connString
  $arr_values = @('1','1') 
  $tbl_name = "dbo.test1"
 
  $conn.Open()
  try
  {
    if($conn.State -eq "Open")
    {         
     foreach ($Id in $arr_values) 
     {
        $scope = New-Object -TypeName System.Transactions.TransactionScope
       
        $Drop_Command= "DROP Table IF EXISTS $tbl_name"
        Invoke-Sqlcmd -ServerInstance <Server-Name> -Database <DB-Name> -Query $Drop_Command
        
        $Create_Command = "Create table dbo.test1 (Id int, CONSTRAINT PK_test1_Id PRIMARY KEY (Id))"
        Invoke-Sqlcmd -ServerInstance <Server-Name> -Database <DB-Name> -Query $Create_Command
        
        
        $Insert_Command = "INSERT INTO dbo.test1(Id) Values ($Id)"
        Write-Host "$Insert_Command->" $Insert_Command
        Invoke-Sqlcmd -ServerInstance <Server-Name> -Database <DB-Name> -Query $Insert_Command
        # Start-Sleep -Seconds 10
        
        Write-Host "Record Inserted with Id->" $Id
     }
     $scope.Complete()
     # $scope.Dispose()     
   }            
 }     
 catch
 {
      Write-Host "Record not Inserted ->" $Id
      $_.exception.message
 }
 finally
 {
    $scope.Dispose() 
    $conn.Close()
 }

添加到大卫的答案中,您可以使用SqlTransactionSqlCommand对象而不是Invoke-SqlCmd 这是基于您问题中的代码的一些示例代码。 我没有尝试纠正原始代码中的错误(例如,表 dbo.test1 create 将在第二次迭代中失败)。

$connString = "Data Source=<Server-Name>;Database=<DB-Name>;User ID=<Login>;Password=<Pass>"
 
$conn = New-Object System.Data.SqlClient.SqlConnection $connString
$arr_values = @('1','1') 
$tbl_name = "dbo.test1"
 
$conn.Open()
$tran = $conn.BeginTransaction()

try {

    foreach ($Id in $arr_values) {

        $script = @"
            DROP Table IF EXISTS $tbl_name;
            Create table dbo.test1 (Id int, CONSTRAINT PK_test1_Id PRIMARY KEY (Id));
            INSERT INTO dbo.test1(Id) Values ($Id);
"@

        $cmd = New-Object System.Data.SqlClient.SqlCommand($script, $conn)
        $cmd.Transaction = $tran
        [void]$cmd.ExecuteNonQuery()
        Write-Host "Record Inserted with Id->" $Id
        }
    $tran.Commit()

}    

catch {
    $tran.Rollback()
    Write-Host "Record not Inserted ->" $Id
    $_.exception.message
}
finally {
    $conn.Close()
}

Invoke-SqlCmd是一种方便的方法。 构建一个包含所有事务处理的脚本并将其传递给Invoke-SqlCmd ,或者直接使用SqlConnectionSqlCommandSqlTransaction对象。

而且我不确定TransactionScope在 PowerShell 中是否有效。

我对 PowerShell 一无所知,但您似乎试图以错误的方式解决问题。

SQL 有 2 组命令:DDL - 数据定义语言和 DML - 数据操作语言。

事务(如果 db 引擎支持它们)可以与 DML 一起正常工作。 要使用 DDL 支持事务,您不应依赖它。 这有点理论。

你可以做什么 - 重新排序和改变一点,以保证你想要什么:

  1. 用另一个名字创建一个表
  2. 尝试插入数据。 如果失败,请删除该表。
  3. 如果插入成功,则删除原始表并将新表重命名为原始表。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM