程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> MYSQL數據庫 >> MySQL綜合教程 >> mysql多層開發更新數據問題

mysql多層開發更新數據問題

編輯: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

測試的 Form 內放了 TSQLConnection、TSQLQuery、TDataSetProvider、TClientDataSet、TDataSource、TDBGrid、TDBNavigator 各一個
TSQLConnection 指定 Connection Name 使它和資料庫連接
TSQLQuery 連上 TSQLConnection, 指定 SQL (為最簡單的 SELECT * FROM ...), 然後在TSQLQuery的fields屬性中添加所有所有的字段, 除了 PK 不動, 其它的列的 ProviderFlags 去掉 pfInWhere(注意喔, PK 的 pfInWhere 要保持勾選喔, 非 PK 的則去掉)
TDataSetProvider 連上 TSQLQuery
TClientDataSet 連上 TDataSetProvider, 並撰寫 AfterPost (內容就是資料庫交易和 ApplyUpdate) 及 ReconcileError (呼叫 HandleReconcileError)
TDataSource,TDBGrid,TDBNavigater 設好基本屬性..

Build 出執行檔後, 執行兩份(A和B), 進行測試...
針對同一筆資料, A 先異動(PK不異動), 儲存後, B 異動(不管含不含PK), 可成功的儲存 (A,B都按一下更新鈕, 會發現資料以 B 的為最新)
針對同一筆資料, A 先異動(包含PK), 儲存後, B 異動(不管含不含PK), 出現 "Record not found or changed by another user" 訊息
按取消, 或者選修正並將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.
李維先生在研討會和著作的書籍中也建議大家使用 TSQLQuery+TDataSetProvider+TClientDataSet 的方式
雖然 TSimpleDataSet 一樣是由這三個元件包裝而成, 但許多 Property Method Event 被隱藏了.
當修改 TSimpleDataSet 拉出來的 TField 的 ProviderFlags 時, 實際上是修改到了 TClientDataSet 這一層的 TField.ProviderFlags
而我們要修改的應該是 TSQLQuery 的 TField.ProviderFlags
因此不論你怎麼改, TSQLMonitor 所觀察到的 SQL 語句都不受影響
所以建議你棄用 TSimpleDataSet
我個人一向不使用 TSimpleDataSet (以李先生的建議是, 對於一些 Simple 的事務, 可交由它處理, 其它的事務還是以分成三元件的撰寫方式為佳)
使用 TSQLQuery+TDataSetProvider+TClientDataSet 還有別的好處
當要改用 ADO 時, 只要把 TSQLQuery 換成 TADOQuery 即可
當要改成三層式時, 只要把 TSQLQuery 和 TDataSetProvider 搬到中間層即可"

方法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)

作者“清風亂翻書”

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved