【问题标题】:ensuring that all invoke-sqlcmd commands happen within the same transaction?确保所有invoke-sqlcmd 命令都发生在同一个事务中?
【发布时间】:2021-12-13 19:06:14
【问题描述】:

我们如何确保在 1 个数据库事务中执行以下函数?

#
# Get SQL Files recursively
#
function GetFiles($path = $pwd) 
{ 
    $subFolders = Get-ChildItem -Path $path -Directory  | Select-Object FullName,Name | Sort-Object -Property Name 
    $sqlFiles = Get-ChildItem -Path $path -Filter *.sql | Select-Object FullName,Name | Sort-Object -Property Name
    
    foreach ($file in $sqlFiles)
    {
      Write-Host "file: " $file.Name
      Invoke-Sqlcmd -ServerInstance $ServerInstance -Database $DBName -Username $SvcAdminAccount -Password $SvcAdminPassword -InputFile $file.FullName -QueryTimeout 65535 -ea stop
    } 

    foreach ($folder in $subFolders)
    {
       Write-Host "`nGetting files for subfolder: " $folder.Name
       GetFiles $folder.FullName
    } 
}

这个函数遍历一个目录并且会为每个文件调用-sqlcmd。 我们如何保证整个函数在一个sql事务中执行>?

【问题讨论】:

  • 您需要创建一个大批次以通过invoke-sqlcmd 传递。您可能最好使用 ForEach 创建 SQL 文件,并且必须确保在批处理开始时启用 XACT_ABORT 并声明事务,这样如果任何语句失败,一切都会回滚.
  • 每个Invoke-Sqlcmd 都是与数据库的单独会话。事务不能跨越会话。正如@Larnu 建议的那样,如果您在 SQL Server 上,请创建一个带有适当放置的 BEGIN TRANSACTION;END TRANSACTION; 语句的 .sql 脚本。
  • 或者你可以使用SqlCommandSqlConnection,在那里你可以使用BeginTransaction

标签: .net sql-server powershell


【解决方案1】:

我们可以利用标准的 ADO.Net 类 SqlConnectionSqlCommand

最好将这些放在try/finally 块中,为此我使用了Using-Object 函数from this answer

$sqlFiles = Get-ChildItem -Path $path -Filter *.sql | Select-Object FullName,Name | Sort-Object -Property Name;

$connString = "Server=YourServer;Database=$DBName;User Id=$SvcAdminAccount;Password=$SvcAdminPassword";

Using-Object ($conn = New-Object System.Data.SqlClient.SqlConnection $connString) {
    $conn.Open();
    
    Using-Object ($tran = $conn.BeginTransaction()) {
        foreach ($file in $sqlFiles)
        {
          Write-Host "file: " $file.Name
          $comm = New-Object System.Data.SqlClient.SqlCommand $file,$conn,$tran;
          $comm.ExecuteNonQuery();
        }
        $tran.Commit();
    };
};
function Using-Object
{
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [AllowEmptyString()]
        [AllowEmptyCollection()]
        [AllowNull()]
        [Object]
        $InputObject,

        [Parameter(Mandatory = $true)]
        [scriptblock]
        $ScriptBlock
    )

    try
    {
        . $ScriptBlock
    }
    finally
    {
        if ($null -ne $InputObject -and $InputObject -is [System.IDisposable])
        {
            $InputObject.Dispose()
        }
    }
}

【讨论】:

  • New-Object : 找不到“SqlCommand”的重载和参数计数:“3”。
  • 抱歉现在应该修复
猜你喜欢
  • 2012-12-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多