programing

트랜잭션 내에서 "GO"사용

goodcopy 2021. 1. 17. 11:56
반응형

트랜잭션 내에서 "GO"사용


App_Start에서 데이터베이스를 설치 / 업그레이드하려는 웹 앱을 구축 중입니다. 설치 절차의 일부는 데이터베이스에 asp.net 기능이 설치되어 있는지 확인하는 것입니다. 이를 위해 System.Web.Management.SqlServices 개체를 사용하고 있습니다.

내 의도는 SQL 트랜잭션 내에서 모든 데이터베이스 작업을 수행하고 실패하는 경우 트랜잭션을 롤백하고 데이터베이스를 그대로 두는 것입니다.

SqlServices 개체에는 트랜잭션이 아닌 ConnectionString을 사용하는 "Install"메서드가 있습니다. 그래서 대신 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 문을 사용하는 데 문제가 있다고 가정합니다.

이 생성 된 스크립트를 이런 방식으로 실행할 때 어떻게 작동시킬 수 있습니까?


GO는 SQL 키워드가 아닙니다.

클라이언트 도구 (예 : SSMS)에서 전체 스크립트를 배치로 나누는 데 사용하는 배치 구분 기호입니다.

스크립트를 직접 배치로 나누거나 "-c GO"와 함께 sqlcmd 또는 "GO"를 처리하기 위해 osql과 같은 것을 사용해야합니다.


트랜잭션의 이름을 지정하면 내부에 여러 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

이 문제를 해결하는 가난한 사람의 방법 : 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()목록 바로 위에 있습니다. 멋지고 보너스 포인트를 위해 거래를 사용하십시오.

# # # # # 보너스 포인트 # # # # # #

트랜잭션 비트를 처리하는 방법은 실제로 운영 목표에 달려 있습니다. 기본적으로 두 가지 방법으로 수행 할 수 있습니다.

a) 전체 실행을 단일 트랜잭션으로 래핑합니다. 이는 모든 것이 실제로 실행되거나 실패하기를 원할 경우 의미가 있습니다 (더 나은 옵션 IMHO).

b) 각 호출을 ExecuteNonQuery()자체 트랜잭션으로 래핑 합니다. 사실, 각 호출은 자체 트랜잭션입니다. 그러나 예외를 포착하고 다음 항목으로 넘어갈 수 있습니다. 물론 이것이 전형적인 DDL 생성이라면, 종종 다음 부분은 이전 부분에 의존하므로 한 부분이 실패하면 아마도 전체 멍청이를 괴롭힐 것입니다.


아래에서 지적한대로 편집 은 배치가 실제로 올바른 tran을 지정했습니다.

문제는 GO가 일괄 처리의 끝을 나타 내기 때문에 트랜잭션 내에서 GO를 사용할 수 없다는 것이 아니라 그 자체가 T-SQL 명령이 아닙니다. SQLCMD를 사용하여 전체 스크립트를 실행하거나 GO에서 분할하고 각 배치를 차례로 실행할 수 있습니다.


GO는 SQL의 일괄 구분 기호입니다. 그것은 하나의 전체 배치의 완료를 의미합니다. 예를 들어 하나의 일괄 @ID에 정의 된 변수는 'GO'문 이후에 액세스 할 수 없습니다. 이해를 위해 아래 코드를 참조하십시오

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

스크립트 테스트 :

  • 백업 서버에서 프로덕션 백업 복원
  • GO로 실행 스크립트 실행

스크립트를 설치하십시오.

  • 응용 프로그램 종료
  • 단일 사용자 모드로 이동
  • 백업 데이터베이스
  • 실패 복원 백업시 GO로 스크립트 실행
  • 다중 사용자 모드로 돌아 가기
  • 응용 프로그램 다시 시작

실제로 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

All you need is the SQL CLR Types and SQL Management objects packages deployed from: http://www.microsoft.com/en-us/download/details.aspx?id=29065 (SQL 2012 version)


Just thought I'd add my solution here... replace the 'GO' with a separator that ExecuteNonQuery understands i.e. the ';' operator. Use this function to fix your script:

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

It may not work for complex nested T-SQL with ';' operators in them, but worked for me and my script. I would have used the splitting method listed above, but I was restricted by the library I was using so I had to find another workaround. Hope this helps someone!

PS. I am aware that the ';' operator is a statement separator and the 'GO' operator is a batch separator, so any advanced scripts will probably not be fixed by this.

ReferenceURL : https://stackoverflow.com/questions/971177/using-go-within-a-transaction

반응형