【问题标题】:Initiate Rollback if any SQL command fails如果任何 SQL 命令失败,则启动回滚
【发布时间】:2013-05-14 04:09:41
【问题描述】:

我正在考虑更新我为将 Exchange 消息跟踪日志插入 SQL 而运行的旧 PowerShell 脚本。由于我将消息跟踪日志拉入以制表符分隔的 CSV 文件然后导入它们的方式,我有一个相当大的 SQL 语句,我想回滚并在出现错误或问题时抛出异常...

我按以下顺序执行此操作:

  1. 截断我之前在脚本中创建的临时表。
  2. 将 CSV 文件中的日志批量插入到临时表中。
  3. 将邮件跟踪行插入到邮件跟踪表中 来自临时表
  4. 将收件人信息从 Temp 插入收件人表 表。
  5. 更新我的服务器表以反映我已经成功的事实 及时上前,插入原木。

以下是我在 PowerShell 中的函数,即使您不了解 PowerShell,也应该很容易看到正在运行的内容:

Function Import-TrackingLogs
{
    $Command = New-Object System.Data.SQLClient.SQLCommand
    $Command.Connection = $Connection
    $Command.CommandTimeOut = 2000
    $Command.CommandText = "
    TRUNCATE TABLE $TempTable1;

    BULK INSERT $TempTable1
    FROM '$ExportTrackingFile'
    WITH
    (
        FIRSTROW = 2,
        FIELDTERMINATOR = '\t'
    );

    INSERT INTO E12_MessageTracking
    SELECT
    CASE LEN([TimeStamp]) WHEN 2 THEN NULL ELSE REPLACE([TimeStamp], '" + [char]34 + "', '') END AS [TimeStamp],
    CASE LEN([Sender]) WHEN 2 THEN NULL ELSE REPLACE([Sender], '" + [char]34 + "', '') END AS [Sender],
    CASE LEN([Recipients]) WHEN 2 THEN NULL ELSE REPLACE([Recipients], '" + [char]34 + "', '') END AS [Recipients],
    CASE LEN([MessageSubject]) WHEN 2 THEN NULL ELSE REPLACE([MessageSubject], '" + [char]34 + "', '') END AS [MessageSubject],
    CASE LEN([EventId]) WHEN 2 THEN NULL ELSE REPLACE([EventId], '" + [char]34 + "', '') END AS [EventId],
    CASE LEN([Source]) WHEN 2 THEN NULL ELSE REPLACE([Source], '" + [char]34 + "', '') END AS [Source],
    CASE LEN([MessageId]) WHEN 2 THEN NULL ELSE REPLACE([MessageId], '" + [char]34 + "', '') END AS [MessageId],
    CASE LEN([InternalMessageId]) WHEN 2 THEN NULL ELSE REPLACE([InternalMessageId], '" + [char]34 + "', '') END AS [InternalMessageId],
    CASE LEN([RecordGuid]) WHEN 2 THEN NULL ELSE REPLACE([RecordGuid], '" + [char]34 + "', '') END AS [RecordGuid],
    CASE LEN([ClientIp]) WHEN 2 THEN NULL ELSE REPLACE([ClientIp], '" + [char]34 + "', '') END AS [ClientIp],
    CASE LEN([ServerHostname]) WHEN 2 THEN NULL ELSE REPLACE([ServerHostname], '" + [char]34 + "', '') END AS [ServerHostname],
    CASE LEN([ConnectorId]) WHEN 2 THEN NULL ELSE REPLACE([ConnectorId], '" + [char]34 + "', '') END AS [ConnectorId],
    CASE LEN([RecipientStatus]) WHEN 2 THEN NULL ELSE REPLACE([RecipientStatus], '" + [char]34 + "', '') END AS [RecipientStatus],
    CASE LEN([RecipientCount]) WHEN 2 THEN NULL ELSE REPLACE([RecipientCount], '" + [char]34 + "', '') END AS [RecipientCount],
    CASE LEN([TotalBytes]) WHEN 2 THEN NULL ELSE REPLACE([TotalBytes], '" + [char]34 + "', '') END AS [TotalBytes],
    CASE LEN([FromServer]) WHEN 2 THEN NULL ELSE REPLACE([FromServer], '" + [char]34 + "', '') END AS [FromServer]
    FROM $TempTable1;

    INSERT INTO E12_MessageTracking_Recipients
    SELECT
    SUBSTRING (s.[TimeStamp], 2, LEN(s.[TimeStamp]) -2) AS [TimeStamp],
    CASE LEN(s.[MessageId]) WHEN 2 THEN NULL ELSE (SUBSTRING (s.[MessageId], 2, LEN(s.[MessageId]) -2)) END AS [MessageId],
    CASE LEN(s.[InternalMessageId]) WHEN 2 THEN NULL ELSE (SUBSTRING (s.[InternalMessageId], 2, LEN(s.[InternalMessageId]) -2)) END AS [InternalMessageId],
    CASE LEN(s.[RecordGuid]) WHEN 2 THEN NULL ELSE (SUBSTRING (s.[RecordGuid], 2, LEN(s.[RecordGuid]) -2)) END AS [RecordGuid],
    f.Value AS [Recipient]
    FROM #E12_MessageTracking AS s
    CROSS APPLY dbo.SplitStrings(SUBSTRING(s.[Recipients], 2, LEN(s.[Recipients]) -2), '|') AS f;

    UPDATE E12_MessageTracking_Servers
    SET LogUpdatedTime = '$EndTime';"

    $Command.ExecuteNonQuery() | Out-Null
}

我可以将每个单独的命令包装到 Powershell 的 try/catch 块中,但我认为最好看看 SQL 是否可以为我处理。

这是我之前在 PowerShell 中的回滚:

$Command = New-Object System.Data.SQLClient.SQLCommand
$Command.Connection = $Connection
$Command.CommandTimeOut = 30
$Command.CommandText = "
DELETE FROM E12_MessageTracking WHERE TimeStamp >= '$StartTime';
DELETE FROM E12_MessageTracking_Recipients WHERE TimeStamp >= '$StartTime';
UPDATE E12_MessageTracking_Servers
SET LogUpdatedTime = '$StartTime';"

$Command.ExecuteNonQuery() | Out-Null

我正在查看此页面 SQL Server - transactions roll back on error?,但不确定如何将其包装到我的命令中,因为我不仅运行一件事,而且运行多个命令。

谢谢!

【问题讨论】:

    标签: sql sql-server sql-server-2008 powershell


    【解决方案1】:

    考虑使用xact_abort:

    set xact_abort on
    begin transaction
    <your big sql statement here>
    commit transaction
    

    【讨论】:

    • 我添加了它,它似乎可以解决问题,谢谢!我故意在语句中间插入了一个除以零,它没有应用以前的更改,并允许我在 PowerShell 中捕获异常。 2013-05-19 16:50:53 - 除以零错误。在 C:\Path\To\Script\ScriptName.ps1:87 char:26 + $Command.ExecuteNonQuery
    • 是否应该在SQL语句的末尾进行错误检查&if语句如果有错误则发出rollback,否则commit?
    • @alroc:XACT_ABORT 就是这样做的。如果有错误,它会回滚事务。
    • 我猜如果它没有被提交并且连接被断开连接它不需要这样做吗?我对数据库运行了 DBCC OPENTRAN,即使它确实运行了 BEGIN TRANSACTION 并随后发生了异常,它也一无所获。
    猜你喜欢
    • 2011-12-22
    • 1970-01-01
    • 2017-10-18
    • 2011-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-15
    • 1970-01-01
    相关资源
    最近更新 更多