确保所有invoke-sqlcmd 命令都发生在同一个事务中?
Posted
技术标签:
【中文标题】确保所有invoke-sqlcmd 命令都发生在同一个事务中?【英文标题】:ensuring that all invoke-sqlcmd commands happen within the same transaction? 【发布时间】: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 脚本。
或者你可以使用SqlCommand
和SqlConnection
,在那里你可以使用BeginTransaction
【参考方案1】:
我们可以利用标准的 ADO.Net 类 SqlConnection
和 SqlCommand
最好将这些放在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”。 抱歉现在应该修复以上是关于确保所有invoke-sqlcmd 命令都发生在同一个事务中?的主要内容,如果未能解决你的问题,请参考以下文章
Powershell运行Invoke-Sqlcmd命令的先决条件
PowerShell 中对 Invoke-Sqlcmd 的 Unicode 支持
Powershell invoke-sqlcmd 打印错误的输出