mysql多层开发更新数据问题

问题:
开发环境:delphi7se + mysql 5.0.67 + dbexpress 2.0 + mysql50open
开发控件:tsimpledataset+datasoure+dbgrid/dbedit
权限:mysql已经授权用户有select/update权限.
但是如果数据有修改,applyupdates(0)始终报告出错.
加入outputdebugstring(pchar(strList)),在view/debug windows/event log中监测到两条错误信息:
"Record not found or changed by another user."
"Unable to find record. No key specified."

解决方法:
from http://delphi.ktop.com.tw/board.php?cid=30&fid=66&tid=35255

�y�的 Form �确帕� TSQLConnection、TSQLQuery、TDataSetProvider、TClientDataSet、TDataSource、TDBGrid、TDBNavigator 各一��
TSQLConnection 指定 Connection Name 使它和�Y料�爝B接
TSQLQuery �B上 TSQLConnection, 指定 SQL (�樽詈��蔚� SELECT * FROM ...), 然後在TSQLQuery的fields属性中添加所有所有的字段, 除了 PK 不��, 其它的列的 ProviderFlags 去掉 pfInWhere(注意喔, PK 的 pfInWhere 要保持勾�x喔, 非 PK 的�t去掉)
TDataSetProvider �B上 TSQLQuery
TClientDataSet �B上 TDataSetProvider, �K撰�� AfterPost (�热菥褪琴Y料�旖灰缀� ApplyUpdate) 及 ReconcileError (呼叫 HandleReconcileError)
TDataSource,TDBGrid,TDBNavigater �O好基本�傩�..

Build 出�绦�n後, �绦�煞�(A和B), �M行�y�...
��ν�一�P�Y料, A 先����(PK不����), �Υ驷�, B ����(不管含不含PK), 可成功的�Υ� (A,B都按一下更新�o, ���l�F�Y料以 B 的�樽钚�)
��ν�一�P�Y料, A 先����(包含PK), �Υ驷�, B ����(不管含不含PK), 出�F "Record not found or changed by another user" �息
按取消, 或者�x修正�K��PK值改成A所�入的新PK值, 即可通�^

原因:
众说纷纭.但基本有两点需要注意:
引用:"ClientDataSet提交时出现"Record not found or changed by another user"错误提示
分析原因可能是找不到更新数据,从网上搜索到大致原因有一下几个方面:
1、没有主键
2、某些字段不能识别
某些提供解决方案也无非是设置DSP的UpdateMode属性,去掉字段的一些默认值
这些问题,我仔细检查了一下,感觉不可能存在,仔细分析原因:我更新记录是分两种方式
一种是:clientdataset.append;
....
提交后再更新
另外一种是大批量插入表,然后打开数据集更新
而第一种方案不存在这个问题,我开始分析第2种方案可能存在的问题。有如下语句:
INSERT INTO tableA (field1,field2) SELECT field1,'' FROM tableb
前几天发现ClientDataSet的CommandText用SELECT ''是不能识别的,提示无效的参数
我想是不是这个原因造成,所以将''改为' '一些正常。"

根据mysql的日志分析,我碰到的是第2种情况,但因为字段众多,修改起来比较麻烦,同时我也不想手工写sql语句.
在按照上面的方法修改前datasnap回传的sql语句是
update students set
曾用名 = '99'
where
班级 = '1' and
注册学号 = '080801031286' and
身份证号 = 'xxx' and
姓名 = '顾xx' and
曾用名 = '' and
性别 = '女' and
民族 = '汉族' and
籍贯省 = '江苏' and
籍贯市县 = 'xxx市' and
家庭地址 = 'xxx路51号2单元702' and
联系电话 = '1335' and
毕业学校 = 'xxx' and
父亲姓名 = '' and
父亲单位 = '' and
母亲姓名 = '' and
母亲单位 = ''
可以看到,窗体中所涉及到的所有字段,无论是否修改,全部都回传到mysql,累赘.
在按照上面的方法修改后datasnap回传的sql语句是
update students set
曾用名 = '11'
where
注册学号 = '080801031285'

update students set
曾用名 = 'qq',
父亲姓名 = 'aa',
父亲单位 = 'bbbbb',
母亲姓名 = 'cc',
母亲单位 = 'ddddd'
where
注册学号 = '080801031286'

COMMIT
现在,只涉及到窗体中数值发生修改的字段.
两相对比可以看出,后面的sql语句更简单,效率更高.

另外老外的说法也有道理,这是mysql非标准sql造成的:
As I posted in a reply to this thread in dbexpress, I suspect the
posters problem is the fact that MySQL does not follow the standard
convention of returning the number of records affected by an update.
Most DBMS's return the number of records found that matched the WHERE
clause in the update SQL statement. MySQL doesn't do this. It returns
the number of records that had data changed by the SQL update
statement. So, if an update SQL WHERE clause matches one record, but
the UPDATE clause does not actually make changes to the column values
(for example SET MyField = '123' and MyField already contains '123'),
MySQL returns a RowsAffected count of zero. MIDAS interprets this as
an unable to find record error.

最终结论:
引用
"我想, ���}就出在 TSimpleDataSet.
李�S先生在研���和著作的��籍中也建�h大家使用 TSQLQuery+TDataSetProvider+TClientDataSet 的方式
�m然 TSimpleDataSet 一�邮怯蛇@三��元件包�b而成, 但�S多 Property Method Event 被�[藏了.
��修改 TSimpleDataSet 拉出�淼� TField 的 ProviderFlags �r, ���H上是修改到了 TClientDataSet �@一�拥� TField.ProviderFlags
而我��要修改的���是 TSQLQuery 的 TField.ProviderFlags
因此不�你怎�N改, TSQLMonitor 所�^察到的 SQL �Z句都不受影�
所以建�h你��用 TSimpleDataSet
我��人一向不使用 TSimpleDataSet (以李先生的建�h是, ��於一些 Simple 的事��, 可交由它�理, 其它的事�者�是以分成三元件的撰��方式�榧�)
使用 TSQLQuery+TDataSetProvider+TClientDataSet �有�e的好�
��要改用 ADO �r, 只要把 TSQLQuery �Q成 TADOQuery 即可
��要改成三�邮�r, 只要把 TSQLQuery 和 TDataSetProvider 搬到中�g�蛹纯�"

方法2:(未试过,备用)
from http://www.diybl.com/course/7_databases/database_other/200838/103354.html
''record not found or changed by another user'',这个错误是我在做项目时,遇到的问题,找了一些参考才解决。如下:
所用的控件有:TDataSetProvider,TADOQuery,TClientDataSet
1.当 DataSetProvider.UpdateMode=upWhereAll 时,update时 where 是指定全部字段,比如,你有a、b、c 3个字段,修改了c字段,在app server中修改的命令是update ... set c=新c where a=旧a and b=旧b and c=旧c
如果 旧的a、b、c之一 已经被其他人改掉了,那where就找不到合适的记录来修改了。所以报告“记录被其他人修改”,这个问题和“锁定”是无关的。

2.当 DataSetProvider.UpdateMode=upWhereKeyOnly 时,update时 where 是指定key字段,比如,
你有a、b、c 3个字段,修改了c字段,a是key field在app server中修改的命令是
update ... set c=新c where a=旧a (只比较a字段)你的程序应该设计为客户修改不到主键字段的值,这样
你的客户只能修改到其他字段的值,其他字段不会出现在where中,就不会出现你说的问题了。

(用第2种方法解决,注意如果你的表原来没有主键的,需要双击dataset,添加你的所有field,在有唯一值的field的 ProviderFlasgs 属性里面 InKey 设置为 true (该field必须是有唯一值的,能相当于主键的,也就是能唯一确定该行记录的),TADOQuery,TClientDataSet控件里的唯一值的field字都要设置InKey为true)

你可能感兴趣的:(mysql,数据库,Delphi,休闲,dbexpress)