문제

현재 사용자가 해당 테이블 중 하나의 스키마 일부를 지시할 수 있는 레거시 시스템을 업데이트하고 있습니다.사용자는 이 인터페이스를 통해 테이블에서 열을 생성하고 제거할 수 있습니다.이 레거시 시스템은 ADO 2.8을 사용하고 있으며 SQL Server 2005를 데이터베이스로 사용하고 있습니다. 이 괴물을 현대화하려는 시도가 시작되기 전에는 어떤 데이터베이스를 사용했는지 알고 싶지도 않을 것입니다.하지만 나는 빗나갔다.=) )

동일한 편집 프로세스에서 사용자는 사용자 생성 필드에 저장할 수 있는 유효한 값 목록을 정의(및 변경)할 수 있습니다(사용자가 필드에 포함될 수 있는 항목을 제한하려는 경우).

사용자가 필드에 대한 유효한 항목 목록을 변경할 때 유효한 값 중 하나를 제거하면 새로운 "유효한 값"을 선택하여 이(현재 유효하지 않은) 값이 있는 행을 매핑할 수 있습니다. 이제 다시 유효한 값을 갖습니다.

이전 코드를 살펴보면서 위에서 언급한 변경 사항은 트랜잭션 내에서 수행되지 않기 때문에 시스템을 유효하지 않은 상태로 만드는 데 매우 취약하다는 것을 알았습니다. 자신의 변화...글쎄, 발생할 수 있는 문제를 상상할 수 있습니다.)

문제는 단일 트랜잭션에서 업데이트하도록 노력했지만 코드가 해당 테이블의 스키마를 변경하는 부분에 도달할 때마다 다른 모든 변경 사항(행의 값 업데이트, 스키마가 변경된 테이블인지 아닌지...전혀 관련이 없는 테이블일 수도 있음) 트랜잭션의 해당 지점까지 구성되어 자동으로 삭제된 것처럼 보입니다.삭제되었다는 오류 메시지가 표시되지 않으며 마지막에 트랜잭션을 커밋해도 오류가 발생하지 않습니다.하지만 트랜잭션에서 업데이트되어야 하는 테이블을 살펴보니 새 열만 있습니다.스키마 이외의 변경 사항은 저장되지 않습니다.

지금까지 인터넷에서 답변을 찾는 것은 몇 시간의 낭비였습니다...그래서 여기로 도움을 요청합니다.테이블의 스키마를 업데이트하고 테이블의 행을 업데이트하는(동일한 테이블이든 다른 테이블이든) ADO를 통해 트랜잭션을 수행하려고 시도한 사람이 있습니까?허용되지 않나요?이 상황에서 도움이 될 수 있는 문서가 있습니까?

편집하다:

좋아, 추적을 했는데 이 명령이 데이터베이스로 전송되었습니다(괄호 안의 설명).

(무슨 일이 일어나고 있는지 모르겠습니다. 임시 저장 프로시저를 생성하는 것 같습니다...?)


declare @p1
int set @p1=180150003 declare @p3 int
set @p3=2 declare @p4 int set @p4=4
declare @p5 int set @p5=-1

(사용자 생성 필드에 대한 정의 정보가 포함된 테이블 검색)


exec sp_cursoropen @p1 output,N'SELECT * FROM CustomFieldDefs ORDER BY Sequence',@p3 output,@p4 output,@p5 output select @p1, @p3, @p4, @p5
go

(내 코드는 여기에 있는 목록을 반복하면서 현재 정보를 가져오는 것 같습니다.)


exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursorfetch 180150003,1025,1,1
go
exec sp_cursorfetch 180150003,1028,1,1
go
exec sp_cursorfetch 180150003,32,1,1
go

(여기서 정의에 대해 수정된 데이터를 입력하는 것 같습니다. 각각을 검토하고 사용자 정의 필드 자체에 대한 정의에서 발생한 변경 사항을 업데이트합니다.)


exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=1,@Description='asdf',@Format='U|',@IsLookUp=1,@Length=50,@Properties='U|',@Required=1,@Title='__asdf',@Type='',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=2,@Description='give',@Format='Y',@IsLookUp=0,@Length=0,@Properties='',@Required=0,@Title='_give',@Type='B',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=3,@Description='up',@Format='###-##-####',@IsLookUp=0,@Length=0,@Properties='',@Required=0,@Title='_up',@Type='N',@_Version=1
go 
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=4,@Description='Testy',@Format='',@IsLookUp=0,@Length=50,@Properties='',@Required=0,@Title='_Testy',@Type='',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=5,@Description='you',@Format='U|',@IsLookUp=0,@Length=250,@Properties='U|',@Required=0,@Title='_you',@Type='',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=6,@Description='never',@Format='mm/dd/yyyy',@IsLookUp=0,@Length=0,@Properties='',@Required=0,@Title='_never',@Type='D',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go
exec sp_cursor 180150003,33,1,N'[CustomFieldDefs]',@Sequence=7,@Description='gonna',@Format='###-###-####',@IsLookUp=0,@Length=0,@Properties='',@Required=0,@Title='_gonna',@Type='C',@_Version=1
go
exec sp_cursorfetch 180150003,32,1,1
go

(이 저장이 시작되기 전에 내 코드가 인터페이스를 통해 삭제된 항목을 제거하는 곳입니다.]...이는 또한 이 거래 중에 실제로 일어나는 일이라고 제가 알 수 있는 유일한 것입니다)


ALTER TABLE CustomizableTable DROP COLUMN _weveknown;

(이제 사용자가 만든 열의 속성을 변경해야 하거나 열의 인덱스를 추가/제거해야 하는 방식으로 정의가 변경된 경우 모든 행에 기본값을 제공하는 것과 함께 여기에서 수행됩니다. 해당 열에 아직 값이 없습니다...내가 아는 한, 저장 프로시저가 완료되면 실제로 이런 일이 발생하지 않습니다.)

go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '__asdf'
go
ALTER TABLE CustomizableTable ALTER COLUMN __asdf VarChar(50) NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx___asdf') CREATE NONCLUSTERED INDEX idx___asdf ON CustomizableTable ( 
__asdf ASC) WITH (PAD_INDEX  = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF);
go
select * from IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx___asdf') CREATE NONCLUSTERED INDEX idx___asdf ON 
CustomizableTable ( __asdf ASC) WITH (PAD_INDEX  = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF);
go
UPDATE CustomizableTable SET [__asdf] = '' WHERE [__asdf] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_give'
go
ALTER TABLE CustomizableTable ALTER COLUMN _give Bit NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__give') DROP INDEX idx__give ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_give] = 0 WHERE [_give] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_up'
go
ALTER TABLE CustomizableTable ALTER COLUMN _up Int NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__up') DROP INDEX idx__up ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_up] = 0 WHERE [_up] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_Testy'
go
ALTER TABLE CustomizableTable ADD _Testy VarChar(50) NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__Testy') DROP INDEX idx__Testy ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_Testy] = '' WHERE [_Testy] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_you'
go
ALTER TABLE CustomizableTable ALTER COLUMN _you VarChar(250) NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__you') DROP INDEX idx__you ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_you] = '' WHERE [_you] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_never'
go
ALTER TABLE CustomizableTable ALTER COLUMN _never DateTime NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__never') DROP INDEX idx__never ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_never] = '1/1/1900' WHERE [_never] IS NULL
go
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'CustomizableTable') AND name = '_gonna'
go
ALTER TABLE CustomizableTable ALTER COLUMN _gonna Money NULL
go
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[CustomizableTable]') AND name = N'idx__gonna') DROP INDEX idx__gonna ON CustomizableTable WITH ( ONLINE = OFF );
go
UPDATE CustomizableTable SET [_gonna] = 0 WHERE [_gonna] IS NULL
go

(거래 종료...?)

exec sp_cursorclose 180150003
go

위의 모든 작업 후에는 열 삭제만 발생합니다.트랜잭션에서 이전과 이후의 모든 내용은 무시된 것으로 보이며 SQL 추적에는 트랜잭션 중에 문제가 발생했음을 나타내는 메시지가 없습니다.

도움이 되었습니까?

해결책

코드는 서버측 커서를 사용하고 있으며, 이것이 바로 해당 호출의 목적입니다.첫 번째 호출 세트는 커서를 준비/열는 것입니다.그런 다음 커서에서 행을 가져옵니다.마지막으로 커서를 닫습니다.이러한 sproc은 OPEN CURSOR, FETCH NEXT, CLOSE CURSOR T-SQL 문과 유사합니다.

좀 더 자세히 살펴봐야 할 것 같지만(그럴 것입니다) 서버 측 커서, 캡슐화 트랜잭션 및 DDL에 문제가 있는 것 같습니다.

추가 질문:

  1. 이 경우 서버측 커서를 사용하시겠습니까?
  2. ADO 명령이 모두 동일한 활성 연결을 사용하고 있습니까?

업데이트:

무슨 일이 일어나고 있는지 정확히 모르겠습니다.

생성된 SQL 문을 실행하여 스키마를 변경하고 동적 테이블의 데이터를 업데이트하는 것 외에도 Recordset.Update()를 사용하여 변경 사항을 서버에 다시 푸시할 수 있도록 서버측 커서를 사용하고 있는 것 같습니다.명시적 트랜잭션 내에서 동일한 연결을 사용합니다.

커서 작업이 나머지 트랜잭션에 어떤 영향을 미칠지, 아니면 그 반대인지 잘 모르겠습니다. 솔직히 말해서 이것이 작동하지 않는다는 사실에 놀랐습니다.

얼마나 큰 변화가 있을지는 모르겠지만 서버 측 커서에서 벗어나 테이블 업데이트를 위한 UPDATE 문을 작성하는 것이 좋습니다.

더 이상 도움을 드리지 못해 죄송합니다.

그런데 sp_cursor 호출에서 다음 정보를 찾았습니다.

http://jtds.sourceforge.net/apiCursors.html

다른 팁

귀하가 설명하는 동작은 허용됩니다.코드는 어떻게 스키마를 변경합니까?즉시 SQL을 작성하고 ADO 명령을 통해 실행하시겠습니까?아니면 ADOX를 사용하시나요?

데이터베이스 서버에 액세스할 수 있는 경우 설명된 시나리오를 테스트하는 동안 SQL 프로파일러 추적을 실행해 보십시오.추적이 오류/롤백을 기록하는지 확인하세요.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top