【问题标题】:Update schema and rows in one transaction, SQL Server 2005在一个事务中更新架构和行,SQL Server 2005
【发布时间】:2010-09-08 15:29:19
【问题描述】:

我目前正在更新一个旧系统,该系统允许用户指定其中一个表的部分架构。用户可以通过此界面在表中创建和删除列。这个遗留系统使用 ADO 2.8,并使用 SQL Server 2005 作为其数据库(在尝试对这头野兽进行现代化改造之前,您甚至不想知道它使用的是什么数据库......但我离题了。=))

在同一个编辑过程中,用户可以定义(和更改)可以存储在这些用户创建的字段中的有效值列表(如果用户想要限制字段中可以包含的内容)。

当用户更改字段的有效条目列表时,如果他们删除了其中一个有效值,则允许他们选择一个新的“有效值”来映射其中包含此(现在无效)值的任何行, 以便它们现在再次具有有效值。

在查看旧代码时,我注意到它极易使系统进入无效状态,因为上述更改不是在事务中完成的(所以如果其他人在上述过程中途加入并进行了自己的更改...好吧,您可以想象可能导致的问题)。

问题是,我一直试图让它们在单个事务下更新,但是每当代码到达它更改该表架构的部分时,所有其他更改(更新行中的值,无论是在架构更改与否的表中......它们甚至可以是完全不相关的表)在事务中构成的那一点似乎被默默地删除了。我没有收到表明它们已被删除的错误消息,并且当我最后提交事务时没有引发错误......但是当我去查看应该在事务中更新的表时,只有新列在那里。所做的任何非架构更改都不会保存。

到目前为止,在网上寻找答案被证明是浪费几个小时......所以我转向这里寻求帮助。有没有人尝试过通过 ADO 执行事务,既更新表的架构又更新表中的行(无论是同一个表还是其他表)?不允许吗?是否有任何文档可以在这种情况下有所帮助?

编辑:

好的,我做了一个trace,这些命令被发送到数据库中(括号中的解释)

(我不知道这里发生了什么,看起来它正在创建一个临时存储过程......?)


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 跟踪中没有任何消息表明事务期间出现了问题。

【问题讨论】:

    标签: sql sql-server sql-server-2005 transactions ado


    【解决方案1】:

    代码使用服务器端游标,这就是这些调用的目的。第一组调用是准备/打开光标。然后从游标中获取行。最后关闭光标。这些存储过程类似于 OPEN CURSOR、FETCH NEXT、CLOSE CURSOR T-SQL 语句。

    我必须仔细看看(我会的),但我猜服务器端游标、封装事务和 DDL 有问题。

    还有一些问题:

    1. 您是否打算在这种情况下使用服务器端游标?
    2. ADO 命令是否都使用同一个活动连接?

    更新:

    我不确定发生了什么。

    看起来您正在使用服务器端游标,因此您可以使用 Recordset.Update() 将更改推送回服务器,此外还可以执行生成的 SQL 语句来更改架构并更新动态表中的数据)。在显式事务中使用相同的连接。

    我不确定游标操作会对事务的其余部分产生什么影响,反之亦然,老实说,我很惊讶这不起作用。

    我不知道会有多大的变化,但我建议不要使用服务器端游标,而是为表更新构建 UPDATE 语句。

    很抱歉,我无法提供更多帮助。

    顺便说一句,我在 sp_cursor 调用中找到了以下信息:

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

    【讨论】:

    • 是的,我在文档中读到,为了进行交易,我不能使用客户端光标。而且我还确保他们都使用相同的活动连接。感谢您的帮助,这肯定是一个奇怪的问题 =(
    • 那里的存储过程也有很好的信息...我感觉它正在做类似的事情,但我不确定...在今天之前我从未真正做过跟踪,所以我从未见过在后台调用这些程序。 =) =)
    • 不用担心,您已根据所提供的信息尽力而为。我也在摸不着头脑......是的,我现在正在使用 Recordset.Update 来进行实际的行更新,正如你所说的......我将尝试使用直接生成的 Update 语句,看看它是如何工作的.
    【解决方案2】:

    您描述的行为是允许的。使架构更改的代码如何?动态构建 SQL 并通过 ADO 命令执行?还是使用 ADOX?

    如果您有权访问数据库服务器,请在测试您概述的场景时尝试运行 SQL Profiler 跟踪。查看跟踪是否记录任何错误/回滚。

    【讨论】:

    • 哦,它正在构建 ADO 命令。我会尝试使用跟踪并报告!
    • 好的,使用了跟踪,不过我没有发现任何异常。 =( 我贴出了上面 Profiler 提取的 SQL 语句。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-11
    • 2011-02-02
    • 1970-01-01
    • 2019-09-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多