超级郁闷问题--使用三层,在特定数据下无法更新。一年只出四条这数,ADO超级BUG。(200分)

  • 主题发起人 主题发起人 mxchao
  • 开始时间 开始时间
M

mxchao

Unregistered / Unconfirmed
GUEST, unregistred user!
1、前提
delphi 三层,dsp+ADO。dsp.updatemode =upWhereAll,直接使用dsp.applyupdates(0)进行数据更新。
2、表创建语句
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Table1]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[Table1]
GO
CREATE TABLE [dbo].[Table1] (
[testid] [uniqueidentifier] NOT NULL ,
[svalue] [numeric](19, 8) NOT NULL
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Table1] WITH NOCHECK ADD
CONSTRAINT [PK_Table1] PRIMARY KEY CLUSTERED
(
[testid]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Table1] ADD
CONSTRAINT [DF_Table1_testid] DEFAULT (newid()) FOR [testid]
GO

3、特定数据 numeric类型 ,数据值 7.97115456。
随便新增一条数据,将svalue的值赋值为7.97115456
4、在delphi随便做一个工程,增加bdgrid,增加applyupdate的代码
5、运行,修改这条记录,进行提交,必然出错!提示record changed by other user
6、跟踪sql语句,将sql语句放到查询分析器执行,正确!
7、跟踪delphi代码,发现在执行sql语句后,并没有正确返回。
procedure TSQLResolver.DoExecSQL(SQL: TStringList;
Params: TParams);
var
RowsAffected: Integer;
begin
RowsAffected := IProviderSupport(Provider.DataSet).PSExecuteStatement(SQL.Text, Params);
if not (poAllowMultiRecordUpdates in Provider.Options) and (RowsAffected > 1) then
DatabaseError(STooManyRecordsModified);
if RowsAffected < 1 then
//××××在此返回值是0,正确应该是1
DatabaseError(SRecordChanged);
end;
8.继续跟踪,跟到Ado里边,到了
function TADOCommand.Execute(var RecordsAffected: Integer;
const Parameters: OleVariant): _Recordset;
var
VarRecsAffected: OleVariant;
begin
SetConnectionFlag(cfExecute, True);
try
Initialize;
Result := CommandObject.Execute(VarRecsAffected, Parameters,
CommandObject.CommandType + ExecuteOptionsToOrd(FExecuteOptions));
RecordsAffected := VarRecsAffected;////××××在此返回值是0,正确应该是1
finally
SetConnectionFlag(cfExecute, False);
end;
end;
9、总结
只要在极其特殊的数据下才出这个错误。一年一共遇到4条这种数据,客户不干了。
跟踪的sql语句可以在查询分析器执行,没有问题,执行正常。
直接用ado两层,不用三层,修改提交正常。
已经做了很多项目,只要一个项目出这种问题,郁闷!
郁闷,那位遇到过?给点意见!
 
数据已经被人更改??
 
不用upWhereAll模式,采用key键值定位。upWhereAll的所有字段精确定位与自增长字段冲突了。设置字段的标志,让自增长字段是定位key,但不update。
还有svalue字段的特定值是不是被数据库修正了,让svalue字段只update,不作定位key
 
to orangeutag
1、没有自增字段
2、为了处理并发不能使用key,只能用whereall
3、值没有被更过,其他数据完全可以修改,只有那条7.97115456不能修改。
 
错误信息提示record changed by other user,这里除了应用程序自己,就只有数据库可能修改提交的数据(比如自动截断,浮点数数值精度外被默认改变)。
这种问题一定是由于更新数据时,按照默认的upWhereAll模式所有字段定位方式无法定位到相应的数据记录才会出现的情况。
1)能不能不用svalue定位!
2)能不能把svalue字段的值提前1位截断(或四舍五入),让他不在浮点数数值精度外被默认改变。(你见过浮点数1.3被计算机等价当作1.29999999999的情况吗?)
我怀疑这里应该是有一个7.97115455999999999999存在!
 
应该是跟数据的精度有关了。全部匹配根本匹配不了,建议还是用键匹配吧。
 
关键问题是使用dsp生成的sql语句可以在查询分析器更新,如果生成的sql不能在查询分析器更新可能是由于精度问题,但现在是生成的sql语句没有精度问题,可以更新。
所有的执行过程我认为都是对的,没有精度问题,没有自增字段等,但就是原生ado对象执行的错误,百思不得其解。
 
to mxchao:
我觉得你进入了一个误区,你把dsp生成的sql语句,复制到查询分析器执行,在sql语句当作文本(包括浮点数)被复制时,已经人为跳过了数据传递时的数据精度处理。你并不能保证ado对象执行sql时也像你一样是简单文本复制的。你只是想当然的认为,ado对象在处理数据时没有任何误差。如果ado对象在处理sql语句参数,把浮点数参数真的当作浮点数处理(听起来有点怪!哈哈),而且我认为ado一定是这样做的。那么,就不可避免的在极少数浮点数处理时出现误差。
还有一点,你的字段svalue,其定义是[numeric](19, 8),刚好是7.97115456所能允许的极限,而小数尾数6又刚好是敏感的边界,建议把精度提高一点试试比如[numeric](19, 9),看看还有没有上述情况。
 
to orangutang
sql语句是我从sql server的事件跟踪器中得到的,应该是ado生成提交到sqlserver的,这个语句在sqlserver执行正常,但在程序中返回值为0,郁闷。
 
to mxchao: 这是我从sql server事件探查器中得到的跟踪结果。
exec sp_executesql N'update Table1 set
svalue = @P1
where
testid = @P2 and
svalue = @P3
', N'@P1 float,@P2 uniqueidentifier,@P3 float', 7.971154990000000e+000, '6B2343A1-FCEB-475A-8F36-F1832EBD1004', 7.971154560000000e+000
--是不是在用于定位时,浮点数7.971154560000000e+000与7.97115456并不被认为是相同的。
 
to orangutang
应该不会,ado并不每个字段都判断,而是将sql语句发到sqlserver进行执行,如果执行正确则为1,如果错误则为0。是通过sqlserver给出的反馈,ado作出的执行是否正确的判定。应该不是在ado内部,逐个对字段进行判断。
另你跟踪的sql语句一定可以直接在查询分析器执行,并且提示影响记录为1。
 
to mxchao:
问题出在字段[svalue]的定义上,将[numeric](19, 8)修改成float,不需要指定该字段的精度,上述问题就可以解决,不能更新的问题就不存在了。数据字段值精度也不会受到任何影响。
不过对于numeric型数据库字段,这确实是一个很让人郁闷的bug。
float字段在数据库中其默认精度居然是53,而[numeric](19, 8)仅仅是19,最大也不过是38,二者相差甚远,奇怪!
 
to orangutang
可float有更让人郁闷的问题,经常出现xxx.xxxx9999999999999999999的这种数据,无法解决。
这个问题超级郁闷了。看来要找borland和微软了。
 
float经常有xxx.xxxx9999999999999999999的这种数据,这只不过是存储与显示的问题,不必去管它,如果不是管理员谁会去打开SQL的表呢?只要提取数据的时候(用户界面),固定取小数点后几位就好了。我有时也用numeric类型,但用后觉得不顺手,以后就都用float了。
 
叫计算机来比较两个浮点数是否相等本来就是错误的想法,记得老师说过在比较的时候不能用“等于”,要比较的话,计算他们的误差的范围是多少。所以我觉得不应该把浮点数包含在匹配条件中。
 
后退
顶部