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