在交易中使用“GO”

时间:2009-06-09 16:36:48

标签: .net sql sql-server tsql 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, ...);

然后我使用企业库中的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.

我认为在SQL事务中使用GO语句存在一些问题。

如何以这种方式执行此生成的脚本。

8 个答案:

答案 0 :(得分:62)

GO不是SQL关键字。

客户端工具(如SSMS)使用批处理分隔符将整个脚本分成批次

您必须自己将脚本分成批次或使用sqlcmd和“-c GO”或osql来处理“GO”

答案 1 :(得分:35)

我只想补充一点,如果您为交易命名,您可以在其中包含多个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

答案 2 :(得分:16)

穷人修复此问题的方法:在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;
}

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

然后在列表上只有ExecuteNonQuery()。获得花哨并使用交易获得奖励积分。

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

如何处理交易位实际上取决于运营目标。基本上你可以用两种方式做到:

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

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

答案 3 :(得分:5)

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

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

答案 4 :(得分:4)

GO是SQL中的批处理分隔符。这意味着完成一整批。例如,在一个批次@ID中定义的变量不能在&#39; GO&#39;之后访问。声明。请参阅以下代码以了解

Declare @ID nvarchar(5);
set @ID = 5;
select @ID
GO
select @ID

答案 5 :(得分:1)

测试你的脚本:

  • 在备份服务器上恢复生产备份
  • 使用GO运行脚本

安装脚本:

  • 关闭申请
  • 转到单用户模式
  • 备份数据库
  • 使用GO运行脚本,故障还原备份
  • 返回多用户模式
  • 重启申请

答案 6 :(得分:1)

实际上,当您使用Microsoft.SqlServer.Management.Smo扩展时,可以使用GO语句:

    var script = GetScript(databaseName);
    var conn = new SqlConnection(connectionString.ConnectionString);
    var svrConnection = new ServerConnection(conn);
    var server = new Server(svrConnection);
    server.ConnectionContext.ExecuteNonQuery(script);

http://msdn.microsoft.com/de-de/library/microsoft.sqlserver.management.smo.aspx

您需要的是从以下位置部署的SQL CLR类型和SQL管理对象包: http://www.microsoft.com/en-us/download/details.aspx?id=29065(SQL 2012版)

答案 7 :(得分:-1)

以为我会在这里添加我的解决方案......用 ExecuteNonQuery 理解的分隔符替换'GO',即';'运营商。使用此功能修复脚本:

private static string FixGoDelimitedSqlScript(string script)
{
    return script.Replace("\r\nGO\r\n", "\r\n;\r\n");
}

对于带有';'的复杂嵌套T-SQL,它可能不起作用他们的操作员,但为我和我的脚本工作。我会使用上面列出的拆分方法,但我受到了我使用的库的限制所以我必须找到另一个解决方法。 希望这有助于某人!

PS。我知道';' operator是一个语句分隔符,'GO'操作符是批处理分隔符,因此任何高级脚本都可能不会被修复。