2008-09-11 5 views
2

현재 사용자가 테이블 중 하나의 스키마 일부를 지시 할 수있는 레거시 시스템을 업데이트하고 있습니다. 사용자는이 인터페이스를 통해 테이블에서 열을 생성하고 제거 할 수 있습니다. 이 레거시 시스템은 ADO 2.8을 사용하고 있으며 데이터베이스로 SQL Server 2005를 사용하고 있습니다.이 짐승을 근대화하려는 시도가 시작되기 전에 어떤 데이터베이스를 사용했는지 알고 싶지는 않습니다 ...))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; 

(있는 경우)이 트랜잭션 동안 발생 말할 수는 멀리 또한 유일한 일이 ... 인터페이스를 통해 삭제 제거하는 정의의 그 사용법이 r 생성 된 열의 속성을 변경하거나 열에 대한 색인을 추가/제거해야합니다. 여기에서 수행되며 지정된 열에 아직 값이없는 행에 기본값을 제공합니다. 저장 프로 시저가 끝날 때까지 내가 말할 수있는,이 중 어느 것도 실제로 발생하지 점에 유의.)

 
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 

그 후 o 위의 경우 열의 삭제 만 발생합니다. 트랜잭션 전후의 모든 내용이 무시 된 것처럼 보이며 SQL Trace에 트랜잭션 중에 문제가 있음을 알리는 메시지가 없습니다.

답변

1

코드가 서버 쪽 커서를 사용하고 있습니다. 그 호출이 그 것입니다. 첫 번째 호출 집합은 커서 준비/열기입니다. 그런 다음 커서에서 행을 가져옵니다. 마지막으로 커서를 닫습니다. 이러한 sprocs는 OPEN CURSOR, FETCH NEXT, CLOSE CURSOR T-SQL 문과 유사합니다.

좀 더 자세히 살펴보아야 하겠지만, 내 생각에 서버 측 커서, 캡슐화 트랜잭션 및 DDL과 관련된 문제가 있습니다.

좀 더 질문 :

  1. 당신은이 경우에는 서버 측 커서를 사용하는 의미합니까?
  2. ADO 명령이 모두 동일한 활성 연결을 사용하고 있습니까?

업데이트 :

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

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

커서 조작이 나머지 트랜잭션에서 어떤 영향을 주는지, 또는 그 반대인지는 확실하지 않습니다. 솔직히 말해서 커서 작동이 작동하지 않는 것이 놀랍습니다.

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

죄송합니다. 도움이 될 수 없습니다. 이 ADO 명령을 구축하는 것,

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

+0

예, 트랜잭션에서 트랜잭션을 수행하기 위해 클라이언트 측 커서를 사용할 수 없다는 것을 설명서에서 읽었습니다. 또한 클라이언트 측 커서를 사용할 수 없었습니다. 모두 같은 활성 연결을 사용합니다. 도움을 주셔서 감사합니다. 확실히 이상한 문제였습니다. ( – EdgarVerona

+0

스토어드 프로 시저에 대한 좋은 정보도 있습니다. 그런 느낌이었습니다. , 그러나 나는 확실하지 않았다 ... 나는 실제로 오늘 전에 Trace를 한 적이 없었으므로, 그런 종류의 절차가 후드 아래에서 호출되는 것을 결코 보지 못했다. =) =) – EdgarVerona

+0

걱정하지 말고, 당신은 최선을 다했다. 주어진 정보와 함께 할 수 있습니다. 나는 그것에 대한 나의 머리를 잘 긁어 모으고있다. .. 예, 나는 당신이 말한 것처럼 Recordset.Update를 실제 행 업데이트에 대해 지금 사용하고있다 ... 나는 직접 생성 된 Update 문을 대신 사용해보고 어떻게 작동하는지 보게 될 것이다. . – EdgarVerona

0

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

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

+0

오 :

BTW-

은 내가 sp_cursor 호출에 다음과 같은 정보를 발견했다. 추적을 사용하여 다시보고하겠습니다. – EdgarVerona

+0

그래, 추적을 사용, 나는 이상한 아무것도 보지 못했지만. = (Profiler에 의해 선택된 SQL 문을 위에 게시했습니다.) – EdgarVerona