在交易中使用"GO"

Gre*_*g B 54 .net sql t-sql sql-server transactions

我正在构建一个尝试在App_Start上安装/升级数据库的Web应用程序.部分安装过程是确保数据库安装了asp.net功能.为此,我使用System.Web.Management.SqlServices对象.

我的目的是在SQL事务中执行所有数据库工作,如果其中任何一个失败,则回滚事务并保持数据库不变.

SqlServices对象有一个方法"Install",它接受ConnectionString而不是事务.所以我使用SqlServices.GenerateApplicationServicesScripts,如下所示:

string script = SqlServices.GenerateApplicationServicesScripts(true, SqlFeatures.All, _connection.Database);
SqlHelper.ExecuteNonQuery(transaction, CommandType.Text, script, ...);
Run Code Online (Sandbox Code Playgroud)

然后我使用企业库中的SqlHelper.

但是这会引发一个异常错误的异常,其中一些是错误的

Incorrect syntax near 'GO'.
Incorrect syntax near 'GO'.
Incorrect syntax near 'GO'.
Incorrect syntax near 'GO'.
Incorrect syntax near the keyword 'USE'.
Incorrect syntax near the keyword 'CREATE'.
Incorrect syntax near 'GO'.
The variable name '@cmd' has already been declared. Variable names must be unique within a query batch or stored procedure.
Run Code Online (Sandbox Code Playgroud)

我假设在SQL事务中使用GO语句存在一些问题.

如何以这种方式执行时,如何使生成的脚本生效.

gbn*_*gbn 63

GO不是SQL关键字.

它是客户端工具(如SSMS)使用的批处理分隔符,可将整个脚本分成多个批处理

您必须自己将脚本分解为批量或使用sqlcmd和"-c GO"或osql来处理"GO"

  • 之前的答案尽管已被接受,但对我来说看起来有点不清楚.所以我想添加一个相关的精度:恕我直言,包装交易其他多个批次绝对没有问题.因此,您可以在交易中完美地放置"GO". (8认同)
  • SET XACT_ABORT聪明的处理,就像Red Gate一样. (7认同)

Cod*_*rue 39

我只想补充一点,如果您为交易命名,您可以在其中包含多个GO部分,它们将作为一个单元回滚.如:

BEGIN TRANSACTION TransactionWithGos;
GO

SET XACT_ABORT ON; -- Roll back everything if error occurs in script
GO

-- do stuff
GO

COMMIT TRANSACTION TransactionWithGos;
GO
Run Code Online (Sandbox Code Playgroud)

  • 这仅适用于SQL Server Management Studio和其他此类工具,它不是有效的SQL,因此这在C#中不起作用. (6认同)
  • 我假设你会有这是一个存储过程。 (2认同)

Wya*_*ett 18

穷人修复此问题的方法:在GO语句中拆分SQL.就像是:

private static List<string> getCommands(string testDataSql)
{
    string[] splitcommands = File.ReadAllText(testDataSql).Split(new string[]{"GO\r\n"}, StringSplitOptions.RemoveEmptyEntries);
    List<string> commandList = new List<string>(splitcommands);
    return commandList;
}
Run Code Online (Sandbox Code Playgroud)

[这实际上是从我正在处理的应用程序中复制出来的.我把这个代码搞得一团糟

然后就ExecuteNonQuery()在列表上方.获得花哨并使用交易获得奖励积分.

##### BONUS POINTS ######

如何处理事务位实际上取决于操作目标.基本上你可以用两种方式做到:

a)将整个执行包装在一个事务中,如果你真的想要一切都要执行或失败,这是有意义的(更好的选择恕我直言)

b)将每个呼叫包裹ExecuteNonQuery()在自己的事务中.实际上,每次通话都是自己的交易.但你可以抓住例外并继续下一个项目.当然,如果这是典型的生成DDL的东西,通常下一部分依赖于前一部分,因此一部分失败可能会使整个小狗陷入困境.

  • 如果您有例如包含单词GO(后跟新行)等的注释,则上述内容可能会错误地拆分sql脚本 - 所以请谨慎使用.或者,您可以使用类似以下内容(StringReader实现)来读取和拆分SQL,并且对注释等敏感:https://github.com/DbUp/DbUp/blob/master/src/DbUp /Support/SqlServer/SqlCommandReader.cs (2认同)

cms*_*sjr 5

如下所述编辑我指定了批次实际上正确的tran.

问题不在于您不能在事务中使用GO,因为GO表示批处理结束,并且本身不是T-SQL命令.您可以使用SQLCMD执行整个脚本,或者将其拆分在GO上并依次执行每个批处理.

  • 不要混淆事务和批处理 - go语句指定一批可能包含一个或多个数据库事务的命令 (9认同)

小智 5

GO 是 SQL 中的批处理分隔符。这意味着完成一整批。例如,在'GO' 语句之后不能访问在一个批处理@ID 中定义的变量。请参考下面的代码理解

Declare @ID nvarchar(5);
set @ID = 5;
select @ID
GO
select @ID
Run Code Online (Sandbox Code Playgroud)