不是delphi疯了就是我疯了,关于adoquery的Post

仙侣步惊云 2010-03-15 11:52:31
一个简单的数据录入问题:
先在窗口放置几个Edit,然后:
myADOQuery.Close;
myADOQuery.SQL.Clear;
myADOQuery.SQL.Add('select id,xm,xb,whcd,kscj from tbM where 1<>1');
myADOQuery.Open;
myADOQuery.edit;
myADOQuery.FieldByName('id').AsInteger:=IntToStr(Editid.text);
myADOQuery.FieldByName('xm').Asstring:=Editxm.text;
myADOQuery.FieldByName('xb').Asstring:=Editxb.text;
myADOQuery.FieldByName('whcd').Asstring:=Editwhcd.text;
myADOQuery.FieldByName('kscj').AsInteger:=IntToStr(Editkscj.text);
try
myADOQuery.post;
showmessage('保存成功!');
except
showmessage('保存错误!');
end;

以前一直是这样做录入,没什么问题
最近却发现不可思议的问题:
当采用二层设计时,数据录入量大时(如每秒种1-3条录入),会发现记录丢失的情况,大约是每二、三千条丢失5-10条情况,并且中间没有任何提示错误。
使用的环境是:服务器win2003,客户端winxp sp2,mdac版本2.8

现在是客户已经录了10多万条数据,大约丢失了好几百条记录,中间却不知丢失了那些记录,又是一篇一篇的查。

将myADOQuery的locktype改为ltBatchOptimistic,使用UpdateBatch(arAll)更新后,丢失的记录减少到个位数,但还是有问题。
问题根源:
1、post有问题?
2、mdac版本?
3、用户的电脑操作系统?
4、病毒?


...全文
837 26 打赏 收藏 转发到动态 举报
写回复
用AI写文章
26 条回复
切换为时间正序
请发表友善的回复…
发表回复
仙侣步惊云 2010-03-16
  • 打赏
  • 举报
回复
实际环境是大约有10几个客户端
仙侣步惊云 2010-03-16
  • 打赏
  • 举报
回复
对了,实际代码我没使用edit;
myADOQuery.Open;
myADOQuery.Insert
myADOQuery.FieldByName('id').AsInteger:=IntToStr(Editid.text);
......
为区区一条记录更新还得挂上事务?有点大炮打蚊子,难道post和updatebatch形同虚设?
dinoalex 2010-03-16
  • 打赏
  • 举报
回复
myADOQuery.Open;
myADOQuery.Insert;
// ADOQuery.edit; 不用edit
风之谷 2010-03-16
  • 打赏
  • 举报
回复
没遇到过 帮顶 最好挂上事物
梦幻人生 2010-03-16
  • 打赏
  • 举报
回复
沒遇到過這種問題,還是多測試些數據吧
我個人用adoquey處理數據時,都很少用post,直接用updatebatch
仙侣步惊云 2010-03-16
  • 打赏
  • 举报
回复
结果项目中设计最简单但是最重要的部分出了问题,后面功能做得很好也漂亮,但客户有怨气不满意。
前几天挂上事务再事务后杜绝了问题再现,但至今惊魂未定。
yshuui 2010-03-16
  • 打赏
  • 举报
回复
我一直用Append。
仙侣步惊云 2010-03-16
  • 打赏
  • 举报
回复
该项目主要业务逻辑是:
基本库:tbM;用四个表记录同学成绩tbKmA、tbKmB、tbKmC、tbKmD,用tbM中的Id(身份证号)外键联系tbKmA等四个成绩表,其中只有A合格才B,只有B合格才C,只有C合格才D,用代码判定学员的成绩录库流程。由于客户功能需要方面提了许多要求,所以只花了小部分时间设计录入模块。结果是用Post时,客户反映录入了tbKmC就丢失了tbKmB,导致用户的大量数据不符合业务逻辑。通过设计专门的查错SQL,排不符合业务逻辑的数据逐一排查,发现大约有2%的数据丢失未提交。
查错SQL:
select M.NSID, m.xm, m.xb, M.SCHOOL,
case when a.g1>0 then '合格'
when a.g2>0 then '不合格'
else null
end ksdcA, --a科目成绩
case when b.g1>0 then '合格'
when b.g2>0 then '不合格'
else null
end ksdcb, --b科目成绩
case when c.g1>0 then '合格'
when c.g2>0 then '不合格'
else null
end ksdcc --c科目成绩
from tbjbxx M left join
(select nsid,
count(case when ksdc = '合格' then 1 else null end) g1, --合格次数
count(case when ksdc = '不合格' then 1 else null end) g2 --不合格次数
from tbzk a
group by nsid
) a on m.nsid = a.nsid
left join
(select nsid,
count(case when ksdc = '合格' then 1 else null end) g1, --合格次数
count(case when ksdc = '不合格' then 1 else null end) g2 --不合格次数
from tbcnk b
group by nsid
) b on m.nsid = b.nsid
left join
(select nsid,
count(case when ksdc = '合格' then 1 else null end) g1, --合格次数
count(case when ksdc = '不合格' then 1 else null end) g2 --不合格次数
from tbksthree c
group by nsid
) c on m.nsid = c.nsid
where (ksdca is null and (not ksdcb is null or not ksdcc is null)) or (ksdcb is null and not ksdcc is null)
or (ksdca ='不合格' and (not ksdcb is null or not ksdcc is null)) or(ksdcb='不合格' and not ksdcc is null)

order by m.nsid
dinoalex 2010-03-16
  • 打赏
  • 举报
回复
那有没有试过用execsql.即组装sql语句,而不用insert
仙侣步惊云 2010-03-16
  • 打赏
  • 举报
回复
不知各位数据库高手遇到这个问题到底是怎么想的?
1、Post有问题?稍微看了一下源代码,机制方面不象有问题,而且delphi的post用了20年,不太可能有问题
2、ODBC版本?应该不是,挂上事务后正常了。
怪就怪在这里:
ADOTemp:=TADOQuery.Create(self);
ADOTemp.Connection:=myDataMd.ADOConnection1;
ls_sql:='select id,xm from tbM where id='+DBEdit4.Text;
ADOTemp.SQL.Add(ls_sql);
ADOTemp.Open;
if ADOTemp.RecordCount<1 then //如果基本库有没有记录
begin
ShowMessage('该学员还未建档,请建档后再登记成绩');
DBEdit4.SetFocus; FreeAndNil(ADOTemp); exit;
end;
.....
结果是能够正常从服务器端取回TbM的ID,再根据ID判断别的表的录入操作,当录入了别的表的数据再提交时,才发现前面post的tbM的Id根本没进库,结果导致客户的数据不符合业务逻辑。
只有挂上事务使用updatebatch(arall)然后提交事务数据才可靠地保存入库。
真是百思不得其解

dupengjx 2010-03-16
  • 打赏
  • 举报
回复
收益!。。。。。。。。。
zhangjing1979666 2010-03-16
  • 打赏
  • 举报
回复
我一直用这种模式 ltBatchOptimistic,没发现这种问题
yanele 2010-03-16
  • 打赏
  • 举报
回复
学习了,平常还没有注意到这样的问题!
莫鸣 2010-03-16
  • 打赏
  • 举报
回复
学习了。受教了。
仙侣步惊云 2010-03-16
  • 打赏
  • 举报
回复
try
myConnect.BeginTrans;
....
myADOQuery.Post;//
myADOQuery.UpdateBatch(arALL);
myConnect.CommitTrans;
ShowMessage('Yes');
except
myConnect.RollBackTrans;
ShowMessage('No');
end;
问题没有再现。
delphi底层代码不可靠
huangheguyun 2010-03-16
  • 打赏
  • 举报
回复
很有可能是2,因为我曾遇到过类似的情况,更新ADO数据连接版本后问题解决。
火龙岛主 2010-03-16
  • 打赏
  • 举报
回复
myADOQuery.Close;
myADOQuery.SQL.Clear;
myADOQuery.SQL.Add('select id,xm,xb,whcd,kscj from tbM where 1<>1');
myADOQuery.Open;
myADOQuery.edit;
myADOQuery.FieldByName('id').AsInteger:=IntToStr(Editid.text);
myADOQuery.FieldByName('xm').Asstring:=Editxm.text;
myADOQuery.FieldByName('xb').Asstring:=Editxb.text;
myADOQuery.FieldByName('whcd').Asstring:=Editwhcd.text;
myADOQuery.FieldByName('kscj').AsInteger:=IntToStr(Editkscj.text); //这里也不对啊,应该为:myADOQuery.FieldByName('kscj').AsInteger:=StrToInt(Editkscj.text);

try
myADOQuery.post;
showmessage('保存成功!');
except
showmessage('保存错误!');
end

楼主贴一个模拟代码,如何解惑?
静远 2010-03-16
  • 打赏
  • 举报
回复
应该添加新数据是Append,修改才是Edit?
柯本 2010-03-16
  • 打赏
  • 举报
回复
感觉上2的可能性最大,以前遇过ADO的某些版本对某些数据库操作有问题(其实BDE也碰到过,早期用BCB5.0,用它连接oracle时,查到20条记录居然返回40条,查了一星期,才发现是BDE的一个BUG),所以建议LZ换个数据引擎做测试。首先排除数据引擎的问题。其它几项感觉不太可能。(当然post本身与引擎有关)
天之雪狐 2010-03-16
  • 打赏
  • 举报
回复
事务的处理,并不在于数据的多少,事务出现的本质就是为了解决数据延迟或异步操作的,所以,对于数据库的操作,最好还是加上事务,不要偷这个懒,如果不加上,就算你不用Delphi,而用C++或其他任何编程语言,都会出现数据丢失的情况。
加载更多回复(6)
******************************* 华软源码:http://www.hur.cn 欢迎转载,但请保留出处,谢谢 ******************************* 很久没有发布东东了,今天看到盒子上有朋友发布了个三层的东东, 下来大概看了看,貌似使用起来不太方便,曾经用过ASTA和RmoObject,都不是那么让人满意,BUG多,并且庞大需要安装,使用十分不方便。 为了继续支持我喜欢的DELPHI和可爱的盒子, 特发布个自己写的远程数据库对象希望能给大家平常的工作带来便利和高效(偶自己和同事们都用了挺长时间,十分稳定易用)。 用DELPHI的朋友少不了要和数据库打交道,一般小程序都使用ACCESS做数据库感觉十分方便,不用装服务端,客户端不用单独装驱动, 发布程序时直接目录一拷贝就完事,但缺点是不方便从其它计算机对它进行访问, 有了偶这个东东,就可以很方便容易的实现咯。 ps : 就是连接Oracle和mysql,客户端也可以不用装驱动哦 使用步骤 解压后找个地方存放 将GobUnit目录添加到delphi的搜索路径 将DXSockEnt30(我改过bug的版本)的3个子目录也添加到delphi的搜索路径 即可使用和编译所有偶提供的代码 FAQ: 这个东东都提供什么功能? 答:提供最简单方便高效的方式,通过ADO对象实现远程数据库 这个东东为什么不封装成控件? 答:本类以单元形式封装,只要加到搜索路径后直接引用即可,无需经过安装等麻烦的步骤。 这个东东适合应用在什么场合? 答:适合应用于小型分布式程序。 这个东东掌握起来有难度吗? 答:没有任何难度,就和你开发本地数据程序一样简单。 这个东东可以应用在我已有的程序里吗? 答:由于我使用的是AdoQuery作为数据集载体,所以无需更改为其他控件,现有的本地数据库程序也可以非常容易的改造为支持分布式数据库。 这个东东稳定吗? 答:经自己长期做小白鼠广泛的实际应用实践,发现方便,稳定。 服务端的端口号是多少? 答:服务端的端口号可以随意设置,只要不和其他程序冲突就可以,并且客户端连接服务端时必须端口一致. 如果服务端重启了客户端需要重启吗? 答:不用,客户端只要连接上服务端以后就有自动断线重连的功能。 我在使用时要注意什么? 答:如果你要用ADOQuery对象的Insert,Post方法新增数据时,我会占用这个对象的BeforePost和BeforeDelete事件。 这个东东免费吗? 答:完全免费,并且开放所有源代码,你可以随意改进,传播它,当然如果更好用了,记得给我也发一份 :)(要保留偶的版权和注释信息哦) 这个东东使用到了那些控件? 答:delphiADO控件,INDY,以及第3方Dxsock(服务端用)。 同时发布的还有我自己积累的几个常用单元,有日志,调试,tcp的通用服务和客户端模块等,同样都是十分有用的东东。 这个东东有demo程序吗? 答:有最简单的示范程序,但时间关系只写了最简单的演示代码,还有很多值得你去挖掘的实用接口和单元。 我有了改进版本,怎么联系这个东东的作者? 答:QQ 22900104 ,Email 22900104@qq.com 马敏钊 发布这个东东的目的是什么? 答:好用的东东大家分享,共同学习,共同进步,希望大家都能发扬开源精神。 构架说明: 大概是这样的,偶有一个服务器对象,负责提供数据库服务,在需要提供数据服务的程序里创建它即可。 使用起来十分简单 首先引用服务端单元 uses UntRmodbSvr; //创建远程服务对象 (参数1 服务端口号 日志对象,如果不需要记录日志请填nil) Gob_RmoDBsvr := TRmodbSvr.Create(FSvrPort, nil); //连接数据库 可以是ADO支持的所有数据库 调用TDBMrg提供的获取各种数据库的链接字符串即可,这里连接Access数据库 Gob_RmoDBsvr.ConnToDb(TDBMrg.GetAccessConnStr('cfg.mdb')); 到此为止,2行代码使你的这个程序具有了将数据库发布出去的能力,其它机器的程序可以方便的通过它访问到数据库,像使用本地数据库一样。 客户端只需连接服务端即可,不管服务端是什么样的数据库,无需安装任何数据库驱动。 uses UntRemSql; //创建客户端对象 RmoClient := TRmoHelper.Create(); //连接服务端 填入服务端地址和端口(与服务端端口一致即可) Result := RmoClient.ReConnSvr(ISvrIP, Iport); 2行代码使你的客户端程序具有了方便的访问到远端的数据库,像使用本地数据库一样,并且你原有的单机数据库程序可以很方便改为远程数据库。 具体使用方法可以查看DEMO程序
这是我从网上下载的,我感觉很不错 FAQ: 这个东东都提供什么功能? 答:提供最简单方便高效的方式,通过ADO对象实现远程数据库 这个东东为什么不封装成控件? 答:本类以单元形式封装,只要加到搜索路径后直接引用即可,无需经过安装等麻烦的步骤。 这个东东适合应用在什么场合? 答:适合应用于小型分布式程序。 这个东东掌握起来有难度吗? 答:没有任何难度,就和你开发本地数据程序一样简单。 这个东东可以应用在我已有的程序里吗? 答:由于我使用的是AdoQuery作为数据集载体,所以无需更改为其他控件,现有的本地数据库程序也可以非常容易的改造为支持分布式数据库。 这个东东稳定吗? 答:经自己长期做小白鼠广泛的实际应用实践,发现方便,稳定。 服务端的端口号是多少? 答:服务端的端口号可以随意设置,只要不和其他程序冲突就可以,并且客户端连接服务端时必须端口一致. 如果服务端重启了客户端需要重启吗? 答:不用,客户端只要连接上服务端以后就有自动断线重连的功能。 我在使用时要注意什么? 答:如果你要用ADOQuery对象的Insert,Post方法新增数据时,我会占用这个对象的BeforePost和BeforeDelete事件。 这个东东免费吗? 答:完全免费,并且开放所有源代码,你可以随意改进,传播它,当然如果更好用了,记得给我也发一份 :)(要保留偶的版权和注释信息哦) 这个东东使用到了那些控件? 答:delphiADO控件,INDY,以及第3方Dxsock(服务端用)。 同时发布的还有我自己积累的几个常用单元,有日志,调试,tcp的通用服务和客户端模块等,同样都是十分有用的东东。 这个东东有demo程序吗? 答:有最简单的示范程序,但时间关系只写了最简单的演示代码,还有很多值得你去挖掘的实用接口和单元。 我有了改进版本,怎么联系这个东东的作者? 答:QQ 22900104 ,Email 22900104@qq.com 马敏钊 发布这个东东的目的是什么? 答:好用的东东大家分享,共同学习,共同进步,希望大家都能发扬开源精神。 构架说明: 大概是这样的,偶有一个服务器对象,负责提供数据库服务,在需要提供数据服务的程序里创建它即可。 使用起来十分简单 首先引用服务端单元 uses UntRmodbSvr; //创建远程服务对象 (参数1 服务端口号 日志对象,如果不需要记录日志请填nil) Gob_RmoDBsvr := TRmodbSvr.Create(FSvrPort, nil); //连接数据库 可以是ADO支持的所有数据库 调用TDBMrg提供的获取各种数据库的链接字符串即可,这里连接Access数据库 Gob_RmoDBsvr.ConnToDb(TDBMrg.GetAccessConnStr('cfg.mdb')); 到此为止,2行代码使你的这个程序具有了将数据库发布出去的能力,其它机器的程序可以方便的通过它访问到数据库,像使用本地数据库一样。 客户端只需连接服务端即可,不管服务端是什么样的数据库,无需安装任何数据库驱动。 uses UntRemSql; //创建客户端对象 RmoClient := TRmoHelper.Create(); //连接服务端 填入服务端地址和端口(与服务端端口一致即可) Result := RmoClient.ReConnSvr(ISvrIP, Iport); 2行代码使你的客户端程序具有了方便的访问到远端的数据库,像使用本地数据库一样,并且你原有的单机数据库程序可以很方便改为远程数据库。 具体使用方法可以查看DEMO程序

2,497

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 数据库相关
社区管理员
  • 数据库相关社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧