0

我们正在尝试实施一个修补客户端软件的程序 - 最初将运行一个 .SQL,但如果脚本在任何时候失败,我们将回滚数据库并停止客户端 DLL 导入过程的工作。

我们的 SQL 脚本有“GO”语句,因此我们无法组合一个漂亮的存储过程来使用sp_executesql,因为这不允许“GO” - 相反,如果我们有一个如下所示的 SQL 脚本:

USE [SomeDatabase]

BEGIN TRANSACTION
GO
IF ( OBJECT_ID(N'[dbo].[ProcedureToUpdate]') IS NOT NULL ) 
    DROP PROCEDURE [dbo].[ProcedureToUpdate]
GO
IF @@ERROR <> 0
    AND @@TRANCOUNT > 0 
    ROLLBACK TRAN
GO
IF @@TRANCOUNT = 0 
    BEGIN
        --Flag that the procedure hasn't been dropped, begin another transaction
        BEGIN TRANSACTION
    END
GO

PRINT 'Creating procedure'
GO

CREATE PROCEDURE [dbo].[ProcedureToUpdate]
AS 
    SELECT  *
    FROM    [dbo].[SomeTable] st
            INNER JOIN [dbo].[AnotherTable] at ON st.PK = at.fk

GO

IF @@ERROR <> 0
    AND @@TRANCOUNT > 0 
    ROLLBACK TRAN
GO
IF @@TRANCOUNT = 0 
    BEGIN
        --Flag that the procedure hasn't been created, begin another transaction
        BEGIN TRANSACTION
    END
GO

然后,我们在 .NET 中的事务中为相关数据库执行每个“操作”(由 go 语句拆分) - 如果循环内的任何内容失败,这将回滚数据库。

  Using con As New SqlConnection(ConnectionString)
    con.Open()
    Dim cmd As SqlCommand = con.CreateCommand()
    Dim transaction As SqlTransaction = con.BeginTransaction("Upgrade")
    cmd.Connection = con
    cmd.Transaction = transaction
    Try
      For Each transactionalScript In transactionalScripts
        cmd.CommandText = transactionalScript
        Dim result = cmd.ExecuteNonQuery()
      Next
      transaction.Commit()
    Catch ex As Exception
      Log(String.Format("{0} : Script Failed", DateTime.Now.ToString()))
      Log(String.Format("{0} : Reason: {1}", DateTime.Now.ToString(), ex.Message))
      transaction.Rollback("Upgrade")
      Log(String.Format("{0} : Database rolled back", DateTime.Now.ToString()))
    End Try
  End Using

最后 - 这是我的问题。我们需要处理多达 4 个 .SQL 脚本,每个脚本将用于单个服务器上的不同数据库。如果 4 个脚本中的任何一个失败,我们应该回滚脚本影响的每个数据库 - 有什么建议吗?

4

1 回答 1

0

看看使用TransactionScope

如果您在 a 中使用多个连接,TransactionScope则会征用分布式事务。这有它自己的要求(例如 DTC),但这肯定是您想要开始寻找的地方。

于 2012-09-14T11:59:39.273 回答