【发布时间】:2017-09-08 10:43:44
【问题描述】:
我正在创建一个数据库更新机制,它在一个事务中运行多个 sql 脚本,如果它们都成功,则提交更新。
我面临的问题是,在每个脚本中都可能存在正在处理的错误,但实际上并未被视为错误。
例子:
脚本必须创建一个表并向表中插入一行,但该表已经存在。没关系,脚本应该继续并尝试插入该行,如果该行存在 - 它也可以,它应该没有错误地完成并移至下一个脚本。另一方面 - 如果出现意外错误(例如表存在,但列较少,因此插入失败),它应该抛出错误并回滚事务。
因为 SQL Server 会在每次错误时回滚我的事务(无论是否处理),我无法正确执行更新。
示例脚本如下所示:
USE [Database]
BEGIN TRY
-- CREATING TABLE
CREATE TABLE [dbo].[Users](
[UserId] [int] UNIQUE NOT NULL,
[UserFullName] [nvarchar](100) NOT NULL,
[UserName] [nvarchar](100) NOT NULL,
[UserShortName] [nvarchar](50) NOT NULL,
[UserLogin] [varchar](50) NOT NULL
)
PRINT 'Created table'
END TRY
BEGIN CATCH
IF(ERROR_NUMBER() = 2714)
BEGIN
PRINT 'Table exists, proceeding to insert'
END
ELSE
THROW
END CATCH
-- INSERTING USER
BEGIN TRY
INSERT INTO [dbo].[Users](
[UserId]
,[UserFullName]
,[UserName]
,[UserShortName]
,[UserLogin]
) VALUES (
1,'System Administrator','Admin','SA', 'SA'
)
PRINT 'Inserted user'
END TRY
BEGIN CATCH
IF(ERROR_NUMBER() = 2627)
BEGIN
PRINT 'User exists - nothing to insert'
END
ELSE
THROW
END CATCH
GO
PRINT '-- FINISHED add_users_table.sql'
(脚本只是一个示例,因此可能不是 100% 正确)
如果表或行存在,事务应该继续,但如果抛出不同的错误,它应该回滚。
有没有办法做到这一点?
谢谢!
编辑:
我忘记了机制的关键部分。我从 C# 运行这些脚本(它更像是一个伪代码而不是实际代码,我也知道 SqlCommand 中的 GO 命令不起作用,但它与问题无关):
SqlTransaction transaction =
connection.BeginTransaction(IsolationLevel.ReadUncommited);
SqlCommand command = new SqlCommand("");
command.Connection = connection;
foreach(string script in scripts)
{
command.CommandText = script;
try
{
command.ExecuteNonQuery();
}
catch()
{
transaction.Rollback();
}
}
transaction.Commit();
【问题讨论】:
-
您是否有任何特殊原因不想采用 SqlZim 建议的解决方案,或者将您的 sql 脚本拆分为每个 try-catch 块的一个脚本?
标签: sql-server tsql sql-server-2012 transactions