2010-06-12 49 views
2

最近我遇到了一個奇怪的問題,請參見代碼剪如下:爲什麼使用異步模式執行qry.post?

var 
    sqlCommand: string; 
    connection: TADOConnection; 
    qry: TADOQuery; 
begin 
    connection := TADOConnection.Create(nil); 
    try 
    connection.ConnectionString := 'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=Test.MDB;Persist Security Info=False'; 
    connection.Open(); 
    qry := TADOQuery.Create(nil); 
    try 
     qry.Connection := connection; 
     qry.SQL.Text := 'Select * from aaa'; 
     qry.Open; 

     qry.Append; 
     qry.FieldByName('TestField1').AsString := 'test'; 

     qry.Post; 
     beep; 
    finally 
     qry.Free; 
    end; 
    finally 
    connection.Free; 
    end; 
end; 

首先,創建一個新的Access數據庫名爲TEST.MDB並把它這個測試項目的目錄下,我們可以創建一個新表在其中僅命名爲aaa,其中只有一個名爲TestField1的文本類型字段。

我們在「beep」行設置一個斷點,然後在IDE調試模式下午餐測試應用程序,當ide停在斷點行(qry.post已經執行)時,此時我們使用microsoft access打開TEST.MDB和開放的表AAA,你會發現沒有表AAA任何變化,如果你讓IDE繼續按F9鍵,你可以找到一個新的記錄插入到表AAA後運行,但如果您按下CTRL + F2鍵終止在斷點處的應用程序,你會發現表AAA已經插入沒有記錄,但在正常情況下,一個新的記錄應在表AAA插入qry.post執行之後。誰能解釋這個問題,這讓我困擾了很長時間。謝謝 !!!

BTW,該IDE是德爾福2010年,是由Microsoft Access 2007年在Windows下創建的訪問mdb文件7

回答

0

Marjan,再次感謝您的答覆,但我不能接受這種行爲什麼是連接引擎進程,今天我找到了一些有用的在MSDN網站,請參見:

http://msdn.microsoft.com/en-us/library/ms719649(v=VS.85).aspx

我已經幸運地根據文章解決了這個問題,事實上,屬性的默認值「的Jet OLEDB:隱式提交同步」是假的,根據該解釋該屬性的假定意味着隱式事務將使用異步模式。所以我們可以做的是設置此屬性通過使用代碼是真實的,如下剪:

connection.Properties.Item['Jet OLEDB:Implicit Commit Sync'].Value := true; 

BTW,根據該條款,此屬性只能通過使用連接對象的屬性屬性設置,否則如果它被設置在連接字符串,將出現

1

訪問不會告訴你從那些未提交的交易記錄。在暫停程序的時候,由連接創建的隱式事務還沒有被提交。沒有經過實驗,但我猜測隱式事務將在釋放查詢後被提交。所以如果你在此之後暫停,你應該在MS Access中看到你的記錄。


從瑞安(詳見他對自己的回答)的更多信息後,我做了一些更多的調查。

有一個主鍵(自動編號或其他方式)似乎並不影響行爲。

與自動編號列表的主鍵

connection.Execute('insert into aaa (TestField1) values (''Test'')'); 
    connection.Execute('select * from aaa'); 
    connection.Execute('delete * from aaa'); 
    beep; 
finally 
    connection.Free; 
end; 

停止對「選擇」不顯示新記錄。 停止「刪除」顯示新記錄。 即使在重複刷新之後,停止「嘟嘟」仍然會顯示錶格中的所有記錄。 在「connection.Free」上停止顯示錶中沒有更多記錄。咦? 停止在「中選擇」插入「刪除」和「嘟嘟」聲之間顯示了在表中沒有更多的記錄。

同桌

connection.Execute('insert into aaa (TestField1) values (''Test'')'); 
    beep; 
    connection.Execute('delete * from aaa'); 
    beep; 
    beep; 

停止對每個語句表明,Access不會收到「命令」,直到至少一個其他的語句已被執行。換句話說:「執行」語句後蜂鳴必須是之前的聲明是通過接入處理處理(這可能需要幾個刷新的展現出來,第一刷新是不夠的)。如果您在「Execute」語句之後第一聲蜂鳴聲停止,Access中將不會發生任何事情,如果您在未執行任何其他語句的情況下重置程序,則不會發生。

步入connection.Execute(使用調試DCU上的):執行的SQL語句的作用是現在在返回提示音接入可見。實際上,它早已可見。例如,進入「delete」語句後,記錄將在ADODB代碼中的某個位置標記爲#deleted。

事實上,通過ADODB代碼步進時,記錄在Access中OnExecuteComplete處理程序停止時變得可見。不是在「開始」停止時,而是在之後立即停止在「如果已分配」時停止。這同樣適用於刪除語句。當在AdoDb的OnExecuteComplete處理程序中的if語句上停止時,效果在Access中可見。

阿土確實有一個ExecuteOption異步執行的語句。這在所有這一切都沒有生效(默認情況下不包括它)。而在我們與進程外的一個COM服務器,並與回調處理,如OnExecuteComplete處理器,該處理器是在ADODB的TAdoConnection.Execute方法ConnectionObject.Execute聲明後立即返回語句之前執行。總而言之,我認爲它不是同步或異步執行的問題,而是更多的是何時發佈引用(我們正在處理COM和接口引用計數),還是與線程和進程時序有關的問題問題(在應用程序,訪問和他們之間),或與其組合。

而且調試器可能只是得過且過的事情沒有澄清他們。使用單線程調試功能查看D2010會發生什麼會很有趣,但是在我現在和未來兩週內沒有找到它。

+0

我預計qry.post執行後,一個新的記錄插入,因爲qry.post似乎synchronouse執行,但根據測試,它是異步執行的錯誤,把在「嘟嘟」和「qry.free」行線兩條breakponts,我發現當應用程序暫停在「嘟嘟」(已執行qry.post)新記錄未插入的行,但是當應用程序暫停在「qry.free」的行,記錄是在(qry。免費未執行),爲什麼qry.post不同步執行.... – Ryan 2010-06-13 03:15:32

+0

是否可能是您檢查過快或不刷新MS Access中的表/查詢?我剛剛將你的代碼逐字複製(剛編輯連接)到新鮮的vcl表單應用程序上的按鈕的onclick處理程序上,並在嘟嘟聲上放置了一個斷點。啓動應用程序,點擊按鈕,當它碰到斷點時,移動到MS Access,新創建的表有兩個初始記錄的表仍然打開。只需按下刷新鍵(F5),即可從delphi應用程序新插入的記錄(仍然以嗶聲暫停)顯示出來。使用Access 2007與'Microsoft.ACE.OLEDB.12.0'提供程序。 – 2010-06-13 14:56:01

+0

有沒有足夠的字符空間來填充我的消息,看下一個答案 – Ryan 2010-06-16 07:54:30

0

首先,Marjan,感謝您的回答,我確信我在那段時間點擊了refesh按鈕,但仍然沒有任何變化...... 經過多次實驗後,我發現如果我插入自動遞增ID爲表中的字段作爲主鍵,這種奇怪的行爲不會發生,雖然我已經做到了這一點,還有另外一個奇怪的行爲,我會告訴我的代碼剪,如下:

procedure TForm9.btn1Click(Sender: TObject); 
var 
    sqlCommand: string; 
    connection: TADOConnection; 
begin 
    connection := TADOConnection.Create(nil); 
    try 
    connection.ConnectionString := 'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=Test.MDB;Persist Security Info=False'; 
    connection.Open(); 
    connection.Execute('insert into aaa (TestField1) values (''Test'')'); 
    connection.Execute('select * from aaa'); 
    connection.Execute('delete * from aaa'); // breakpoint 1 
    beep; // breakpoint2 
    finally 
    connection.Free; 
    end; 
end; 

把兩個斷點在「delete」和「beep」行處,當代碼在breakpoint1處駐留時,可以刷新數據庫,並且您會發現該記錄已插入,當代碼停在斷點2時繼續運行,發現記錄仍然在那裏.....如果在這個時候你按下ctrl + f2,記錄將不會被刪除....如果connection.execute是一個真正的同步過程,這不應該發生。對不起,檢查你的答案這麼晚,因爲我在我們的龍舟節...

+0

我會看看。同時:希望龍不會得到你! – 2010-06-16 08:43:07

+0

調查結果太長,無法發表評論。請參閱編輯我的答案。 – 2010-06-16 09:45:37