通过多个数据库上的事务执行SQL脚本

时间:2012-09-14 09:49:20

标签: sql sql-server vb.net

我们正在尝试实施一个修补客户端软件的程序 - 最初将运行.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个脚本中的任何一个失败,我们应该回滚脚本影响的每个数据库 - 任何建议吗?

1 个答案:

答案 0 :(得分:0)

请使用TransactionScope

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