我们正在尝试实施一个修补客户端软件的程序 - 最初将运行.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个脚本中的任何一个失败,我们应该回滚脚本影响的每个数据库 - 任何建议吗?
答案 0 :(得分:0)
请使用TransactionScope
。
如果在TransactionScope
中使用多个连接,则会使用分布式事务。这有它自己的要求(例如DTC),但这肯定是你想要开始寻找的地方。