㈠ vc++ ADO資料庫
1. 生成應用程序框架並初始化OLE/COM庫環境
創建一個標準的MFC AppWizard(exe)應用程序,然後在使用ADO資料庫的InitInstance函數中初始化OLE/COM庫(因為ADO庫是一個COM DLL庫)。
本例為:
BOOL CAdotestDlg::OnInitDialog()
{
::CoInitialize(NULL); //初始化OLE/COM庫環境
}
程序最後要調用 ::CoUninitialize();//釋放程序佔用的COM 資源。
另外:
m_pRecordset->Close(); 注意!!!不要多次關閉!!!!!!!!!!!!
m_pConnection->Close();
m_pRecordset = NULL;
m_pConnection = NULL;
2. 引入ADO庫文件
使用ADO前必須在工程的stdafx.h文件最後用直接引入符號#import引入ADO庫文件,以使編譯器能正確編譯。代碼如下:
#import "C:\Program Files\common files\system\ado\msado15.dll" no_namespace rename("EOF","adoEOF")
ADO類的定義是作為一種資源存儲在ADO DLL(msado15.dll)中,在其內部稱為類型庫。類型庫描述了自治介面,以及C++使用的COM vtable介面。當使用#import指令時,在運行時Visual C++需要從ADO DLL中讀取這個類型庫,並以此創建一組C++頭文件。這些頭文件具有.tli 和.tlh擴展名,讀者可以在項目的目錄下找到這兩個文件。在C++程序代碼中調用的ADO類要在這些文件中定義。
程序的第三行指示ADO對象不使用名稱空間。在有些應用程序中,由於應用程序中的對象與ADO中的對象之間可能會出現命名沖突,所以有必要使用名稱空間。如果要使用名稱空間,則可把第三行程序修改為: rename_namespace("AdoNS")。第四行代碼將ADO中的EOF(文件結束)更名為adoEOF,以避免與定義了自己的EOF的其他庫沖突。
3.利用智能指針進行資料庫操作
在CaboutDlg頭文件中定義兩個ADO智能指針類實例,並在對話框中加入一個ListCtrl。
class CAdotestDlg : public CDialog
{
_ConnectionPtr m_pConnection;
_RecordsetPtr m_pRecordset;
ClistCtrl m_List;
......
}
ADO庫包含三個智能指針:_ConnectionPtr、_CommandPtr和_RecordsetPtr。
_ConnectionPtr通常被用來創建一個數據連接或執行一條不返回任何結果的sql語句,如一個存儲過程。
_CommandPtr返回一個記錄集。它提供了一種簡單的方法來執行返回記錄集的存儲過程和SQL語句。在使用_CommandPtr介面時,可以利用全局_ConnectionPtr介面,也可以在_CommandPtr介面里直接使用連接串。_RecordsetPtr是一個記錄集對象。與以上兩種對象相比,它對記錄集提供了更多的控制功能,如記錄鎖定、游標控制等。
在使用ADO程序的事件響應中OnButton1加入以下代碼:
void CAdotestDlg::OnButton1()
{
m_List.ResetContent();
m_pConnection.CreateInstance(_uuidof(Connection)); //初始化Connection指針
m_pRecordset.CreateInstance(_uuidof(Recordset));//初始化Recordset指針
try
{
m_pConnection->Open("DSN=ADOTest","","",0); //連接叫作ADOTest的ODBC數據源
//注意:這是連接不需要用戶ID或密碼的open 函數
// 否則形式為 ->Open("DSN=test;uid=sa;pwd=123;","","",0);
// 執行SQL語句得到一個記錄集把其指針賦值給m_pRecordset
CString strSql="select * from middle";
BSTR bstrSQL = strSql.AllocSysString();
m_pRecordset->Open(bstrSQL,(IDispatch*)m_pConnection,adOpenDynamic,adLockOptimistic,adCmdText);
//adOpenDynamic:動態 adLockOptimistic樂觀封鎖法 adCmdText:文本查詢語句
while(!m_pRecordset->adoEOF)//遍歷所有記錄
{
//取紀錄欄位值方式之一
_variant_t TheValue; //VARIANT數據類型
TheValue = m_pRecordset->GetCollect("BIG_NAME");//得到欄位BIG_NAME的值
if(TheValue.vt!=VT_NULL)
m_List.AddString((char*)_bstr_t(TheValue));
//將該值加入到列表控制項中
//取紀錄欄位值方式之二
// _bstr_t TheValue1=m_pRecordset->Fields->GetItem("BIG_NAME")->Value;
// CString temp=TheValue1.();
// m_List.AddString(temp);
//數據類型轉換
_variant_t vUsername,vBirthday,vID,vOld;
TRACE("id:%d,姓名:%s,年齡:%d,生日:%s\r\n",
vID.lVal,(LPCTSTR)(_bstr_t)vUsername,vOld.lVal,(LPCTSTR)(_bstr_t)vBirthday);
m_pRecordset->MoveNext();//轉到下一條紀錄
}
m_pRecordset->Close();
m_pConnection->Close();
}
catch (_com_error e)//異常處理
{
AfxMessageBox(e.ErrorMessage());
}
m_pRecordset->Close(); //注意!!!不要多次關閉!!!!否則會出錯
m_pConnection->Close();
m_pRecordset = NULL;
m_pConnection = NULL;
}
程序中通過_variant_t和_bstr_t轉換COM對象和C++類型的數據, _variant_t類封裝了OLE自治VARIANT數據類型。在C++中使用_variant_t類要比直接使用VARIANT數據類型容易得多。
好,編譯後該程序就能運行了,但記住運行前要創建一個叫ADOTest的ODBC數據源。該程序將把表middle中的BIG_NAME欄位值顯示在列表控制項中。
4.執行SQL命令並取得結果記錄集
為了取得結果記錄集,我們定義一個指向Recordset對象的指針:_RecordsetPtr m_pRecordset;
並為其創建Recordset對象的實例: m_pRecordset.CreateInstance("ADODB.Recordset");
SQL命令的執行可以採用多種形式,下面我們一進行闡述。
(1)利用Connection對象的Execute方法執行SQL命令
Execute方法的原型如下所示:
_RecordsetPtr Connection15::Execute ( _bstr_t CommandText, VARIANT * RecordsAffected, long Options )
其中CommandText是命令字串,通常是SQL命令。
參數RecordsAffected是操作完成後所影響的行數,
參數Options表示CommandText中內容的類型,Options可以取如下值之一:
adCmdText:表明CommandText是文本命令
adCmdTable:表明CommandText是一個表名
adCmdProc:表明CommandText是一個存儲過程
adCmdUnknown:未知
Execute執行完後返回一個指向記錄集的指針,下面我們給出具體代碼並作說明。
_variant_t RecordsAffected;
///執行SQL命令:CREATE TABLE創建表格users,users包含四個欄位:整形ID,字元串username,整形old,日期型birthday
m_pConnection->Execute("CREATE TABLE users(ID INTEGER,username TEXT,old INTEGER,birthday DATETIME)",
&RecordsAffected,
adCmdText);
///往表格裡面添加記錄
m_pConnection->Execute("INSERT INTO users(ID,username,old,birthday) VALUES (1, ''''Washington'''',25,''''1970/1/1'''')",&RecordsAffected,adCmdText);
///將所有記錄old欄位的值加一
m_pConnection->Execute("UPDATE users SET old = old+1",&RecordsAffected,adCmdText);
///執行SQL統計命令得到包含記錄條數的記錄集
m_pRecordset = m_pConnection->Execute("SELECT COUNT(*) FROM users",&RecordsAffected,adCmdText);
_variant_t vIndex = (long)0;
_variant_t vCount = m_pRecordset->GetCollect(vIndex);///取得第一個欄位的值放入vCount變數
上兩句可以寫成— _variant_t vCount = m_pRecordset->GetCollect((_variant_t)((long)0));
m_pRecordset->Close();///關閉記錄集
CString message;
message.Format("共有%d條記錄",vCount.lVal);
AfxMessageBox(message);///顯示當前記錄條數
(2)利用Command對象來執行SQL命令
_CommandPtr m_pCommand;
m_pCommand.CreateInstance("ADODB.Command");
_variant_t vNULL;
vNULL.vt = VT_ERROR;
vNULL.scode = DISP_E_PARAMNOTFOUND;///定義為無參數
m_pCommand->ActiveConnection = m_pConnection;///非常關鍵的一句,將建立的連接賦值給它
m_pCommand->CommandText = "SELECT * FROM users";///命令字串
m_pRecordset = m_pCommand->Execute(&vNULL,&vNULL,adCmdText);///執行命令,取得記錄集
在這段代碼中我們只是用Command對象來執行了SELECT查詢語句,Command對象在進行存儲過程的調用中能真正體現它的作用。下次我們將詳細介紹。
(3)直接用Recordset對象進行查詢取得記錄集
實例——
void CGmsaDlg::OnDBSelect()
{
// TODO: Add your control notification handler code here
_RecordsetPtr Rs1; //定義Recordset對象
_bstr_t Connect("DSN=GMS;UID=sa;PWD=;");//定義連接字元串
_bstr_t Source ("SELECT count(*) FROM buaa.mdb010"); //要執行的SQL語句
::CoInitialize(NULL); //初始化Rs1對象
HRESUL hr = Rs1.CreateInstance( __uuidof( Recordset ) );
//省略對返回值hr的判斷
Rs1->Open( Source,
Connect,
adOpenForwardOnly,
adLockReadOnly,
-1 );
_variant_t temp=Rs1->GetCollect(_variant_t((long)0));
CString strTemp=(char* )(_bstr_t)temp;
MessageBox("OK!"+strTemp);
}
例如
m_pRecordset->Open("SELECT * FROM users",
_variant_t((IDispatch *)m_pConnection,true),
adOpenStatic,
adLockOptimistic,
adCmdText);
Open方法的原型是這樣的:
HRESULT Recordset15::Open ( const _variant_t & Source,
const _variant_t & ActiveConnection,
enum CursorTypeEnum CursorType,
enum LockTypeEnum LockType,
long Options )
其中:
①Source是數據查詢字元串
②ActiveConnection是已經建立好的連接(我們需要用Connection對象指針來構造一個_variant_t對象)
③CursorType游標類型,它可以是以下值之一,請看這個枚舉結構:
enum CursorTypeEnum
{
adOpenUnspecified = -1,///不作特別指定
adOpenForwardOnly = 0,///前滾靜態游標。這種游標只能向前瀏覽記錄集,比如用MoveNext向前滾動,這種方式可以提高瀏覽速度。但諸如BookMark,RecordCount,AbsolutePosition,AbsolutePage都不能使用
adOpenKeyset = 1,///採用這種游標的記錄集看不到其它用戶的新增、刪除操作,但對於更新原有記錄的操作對你是可見的。
adOpenDynamic = 2,///動態游標。所有資料庫的操作都會立即在各用戶記錄集上反應出來。
adOpenStatic = 3///靜態游標。它為你的記錄集產生一個靜態備份,但其它用戶的新增、刪除、更新操作對你的記錄集來說是不可見的。
};
④LockType鎖定類型,它可以是以下值之一,請看如下枚舉結構:
enum LockTypeEnum
{
adLockUnspecified = -1,///未指定
adLockReadOnly = 1,///只讀記錄集
adLockPessimistic = 2,悲觀鎖定方式。數據在更新時鎖定其它所有動作,這是最安全的鎖定機制
adLockOptimistic = 3,樂觀鎖定方式。只有在你調用Update方法時才鎖定記錄。在此之前仍然可以做數據的更新、插入、刪除等動作
adLockBatchOptimistic = 4,樂觀分批更新。編輯時記錄不會鎖定,更改、插入及刪除是在批處理模式下完成。
};
⑤Options可以取如下值之一:
adCmdText:表明CommandText是文本命令
adCmdTable:表明CommandText是一個表名
adCmdProc:表明CommandText是一個存儲過程
adCmdUnknown:未知
5. 記錄集的遍歷、更新
根據我們剛才通過執行SQL命令建立好的users表,它包含四個欄位:ID,username,old,birthday
以下的代碼實現:打開記錄集,遍歷所有記錄,刪除第一條記錄,添加三條記錄,移動游標到第二條記錄,
更改其年齡,保存到資料庫。
_variant_t vUsername,vBirthday,vID,vOld;
_RecordsetPtr m_pRecordset;
m_pRecordset.CreateInstance("ADODB.Recordset");
m_pRecordset->Open("SELECT * FROM users",
_variant_t((IDispatch*)m_pConnection,true),
adOpenStatic,
adLockOptimistic,
adCmdText);
while(!m_pRecordset->adoEOF)
{
vID = m_pRecordset->GetCollect(_variant_t((long)0));///取得第1列的值,從0開始計數,
///你也可以直接給出列的名稱,如下一行
vUsername = m_pRecordset->GetCollect("username");///取得username欄位的值
vOld = m_pRecordset->GetCollect("old");
vBirthday = m_pRecordset->GetCollect("birthday");
///在DEBUG方式下的OUTPUT窗口輸出記錄集中的記錄
if(vID.vt != VT_NULL && vUsername.vt != VT_NULL && vOld.vt != VT_NULL && vBirthday.vt != VT_NULL)
TRACE("id:%d,姓名:%s,年齡:%d,生日:%s\r\n",
vID.lVal,
(LPCTSTR)(_bstr_t)vUsername,
vOld.lVal,
(LPCTSTR)(_bstr_t)vBirthday);
m_pRecordset->MoveNext();///移到下一條記錄
}
m_pRecordset->MoveFirst();///移到首條記錄
m_pRecordset->Delete(adAffectCurrent);///刪除當前記錄
///添加三條新記錄並賦值
for(int i=0;i<3;i++)
{
m_pRecordset->AddNew();///添加新記錄
m_pRecordset->PutCollect("ID",_variant_t((long)(i+10)));
m_pRecordset->PutCollect("username",_variant_t("葉利欽"));
m_pRecordset->PutCollect("old",_variant_t((long)71));
m_pRecordset->PutCollect("birthday",_variant_t("1930-3-15"));
}
m_pRecordset->Move(1,_variant_t((long)adBookmarkFirst));///從第一條記錄往下移動一條記錄,即移動到第二條記錄處
m_pRecordset->PutCollect(_variant_t("old"),_variant_t((long)45));///修改其年齡
m_pRecordset->Update();///保存到庫中
備註:多次查詢可把查詢過程做成一個函數ExecuteSQL讓m_pRecordset獲得連接指針m_pConnection查詢結果
void ExecuteSQL(_ConnectionPtr m_pConnection, _RecordsetPtr m_pRecordset,CString strSql)
{
//執行Select 語句
BSTR bstrSQL = strSql.AllocSysString();
try
{
m_pRecordset->Open(bstrSQL,(IDispatch*)m_pConnection,adOpenDynamic,adLockOptimistic,adCmdText);
//adOpenDynamic:動態 adLockOptimistic樂觀封鎖法 adCmdText:文本查詢語句
}
catch(_com_error error)
{
CString errorMessage;
errorMessage.Format("%s",(LPTSTR)error.Description());
AfxMessageBox(errorMessage);
}
}
//出錯處理:
3127——沒有找到目標表
3092——目標表已經存在
例如:
catch(const _com_error e)
{
AfxMessageBox(e.Description());
long errorCode=e.WCode();
if(3127==errorCode) AfxMessageBox("表不存在");
if(3092==errorCode) AfxMessageBox("表已經存在");
return FALSE;
}
㈡ 連接資料庫需要ADO組件中的什麼對象,創建它的方法是什麼/
一、概述
「性能」這一術語有著幾種不同的、差異微妙的含義。當人們談到某個東西性能多少好時,他們想要表達的意思可能就是在一定的時間之內它完成了多少工作。例如,一個性能好的發動機運行起來更穩定,產生的動力更強大。對於開發小組,你同樣也可能應用這個判斷標准:一個性能好的開發小組工作時比較安靜,而且能夠生產出大量高質量的代碼。對我來說,性能至少意味著兩件事情——我的代碼運行起來有多好,我的開發小組和我本人工作效率怎麼樣。無論哪一方面,本文介紹的技巧都將起到一定的幫助作用:幫助你更快地編寫代碼,幫助你編寫更快的代碼——安靜地完成這一切,減少這樣那樣的錯誤。本文介紹的技巧主要面向ADO,特別是如何通過ADO訪問SQL Server。但與此同時,我還將涉及一些適用范圍更廣的COM技巧,它們適用於你所編寫的所有Visual Basic代碼。
為了了解從哪些SQL Server數據訪問代碼編寫技術、哪些體系、哪些開發習慣可以得到最好的性能,我已經花了不少時間。一些情況下,對於應用的整體性能來說,單一的技術意義很小,除非我們通過循環將性能的改善程度成倍放大。例如,在一個客戶機/伺服器應用中,當我們不是通過指定ODBC數據源(DSN)的方式連接資料庫時,大約能夠節省一到二秒的時間。對於應用整體的適用性或性能來說,這部分節省的時間所產生的影響很小。但是,如果我們在一個中間層組件上應用這種技術,這個組件每分鍾(或每小時,每天)都要建立和關閉資料庫連接數百(甚至數千)次,那麼,這種技術將顯著地影響系統的性能表現。因此,對於我在這里討論的每一種技術,請務必考慮這個倍數因子——即,在一定的時間周期內,你的系統將執行同一段代碼多少次。
當你開始尋求改進性能的方案時,請考慮一下你的應用(組件,或者是ASP代碼)大部份的等待和處理時間花在什麼地方。如果你發現應用程序把大量的時間花在等待Open或Execute方法執行完成,那麼,你應該認真地檢查一下伺服器端的查詢策略。包括ADO在內,所有的數據訪問介面等待查詢結果的時間都相同。例如,如果你有一個查詢,SQL Server需要20秒才能完成它,不論用來執行該查詢的是什麼介面,沒有一種介面能夠比其他介面以更快的速度返回結果。雖然有些介面打開連接的速度比較快,有些介面處理結果集的速度比較快,但沒有一種介面能夠影響資料庫引擎編譯和執行查詢的速度。因此,如果你的查詢具有太高的「挑戰性」——例如你沒有對索引進行優化,你沒有使用存儲過程,伺服器負載過重,或者你要求返回的記錄數量太多——那麼,世界上沒有一種ADO技術能夠幫助你提高性能。除非你解決了這些基本的查詢問題,否則沒有一種性能調整技術能夠顯著地改善整體性能。SQL Server的Query Analyzer是一個分析查詢性能的優秀工具。它能夠用圖形的方式顯示查詢的執行過程,並對改進性能的方法提出建議。
如果你能夠確信查詢具有較高的效率,那麼,你可以使用本文介紹的技術進一步調整ADO代碼的性能。這里介紹的技巧將從各個方面幫助你簡化和改進ADO編程,包括:建立和維護連接,構造和提交執行速度更快的查詢,提高處理查詢結果的效率,等等。
二、建立連接
在一個客戶機/伺服器應用中,我們可以用好幾種方法把建立和初始化資料庫連接所需要的時間隱藏起來,使得應用程序既能夠打開連接,又不需要用戶等待應用程序啟動。首先,我們可以嘗試非同步連接。使用非同步連接時,ADO啟動連接操作之後,不等待連接完成就把控制權返回給應用程序——這樣,應用程序就能夠接著執行大部份初始化操作,以更快的速度完成form_load事件處理。如果關閉並重新建立連接的時間小於連接池釋放連接的時間,那麼這個連接實際上是即時的。但在許多情況下(特別是用戶數量不多時),讓連接保持打開狀態更具有現實意義。在中間層組件或ASP頁面內部,如果資料庫查詢多次重復出現,我建議你讓Connection對象保持打開狀態。
另外一個改進連接性能的辦法是,避免使用帶有DSN的ODBC。在Microsoft,ODBC已經轉入了Quick Fix Engineering(QFE,快速修理工程)狀態,它意味著:除非發現重大BUG,該公司將不再在ODBC或它的驅動程序上花時間。另外,考慮性能和部署問題時,ODBC DSN也是一個必須關注的問題。DSN必須安裝到客戶系統上,要求進行注冊表查找,與OLE DB連接相比,它建立連接所需要的時間更長——特別是當你用直接編碼的方式指定ConnectionString時,這一點尤其突出。從實際效果來看,避免使用DSN降低的系統開銷很有限:如果完全取消連接建立過程,對於每個連接,你也許能夠剩下二到五秒時間(假設資料庫連接池中已經沒有連接)。然而,如果你的應用程序需要頻繁地建立連接,節省的時間累計起來就很可觀了。
建立資料庫連接的時候,你要選擇一個數據提供者。Microsoft建議我們使用OLE DB提供者替代默認的ODBC提供者。對比最新的OLE DB本地提供者和功能類似但較早的ODBC提供者,我感到前者令人不愉快的意外之事較少。但無論是哪種情況,你都應該在決定使用某個新的提供者之前對應用進行完整地測試——代碼的性能、支持的功能、行為方式都有可能發生變化。
在中間層和ASP中,在保持連接打開的情況下,我們不能(從實踐來看)創建出可伸縮的組件——至少在多次調用之間是這樣的。一般地,當IIS引用和釋放組件、ASP頁面的實例時,組件和ASP頁面被頻繁地裝入、丟棄。由於基於ADO的代碼每次執行時都必須建立、使用、釋放資料庫連接,最小化連接復雜程度的策略對性能的提高程度達到了可明顯測量的程度。在這些情形下,對於我們連接資料庫的速度來說,連接/會話池有著重要的意義。如果你為Command對象的ConnectionString屬性指定合適的值(即,每次使用同樣的伺服器、初始目錄、登錄ID和其他參數),那麼,連接已經打開且處於可用狀態的機會很大。如果連接池中能夠找到匹配的連接,連接(或重新連接)的時間將接近0(通常小於250 ms)。
然而,如果ADO(或VB)代碼不釋放Connection對象,或者,我們在不同的實例之間改換了ConnectionString,OLE DB必須每次建立一個新的連接。如果出現了這種情況,我們將很快耗盡連接池內可用連接的數量。要確保連接被釋放,我們必須在關閉連接之後把Connection對象設置為Nothing。另外,不要在Recordset Open方法中使用ConnectionString,而是以獨立的方式打開Connection對象;這樣,當我們要關閉Connection對象以及要把它設置成Nothing的時候,引用它就很方便了。
三、構造和提交查詢
在構造查詢的時候,要搞清楚為什麼必須這么做、為什麼不能那麼做是一個很復雜的問題。然而,一些基本的指導方針能夠讓構造高效查詢的過程更加流暢、輕松。一般地,你不應該讓查詢浪費伺服器時間。下面幾個技巧能夠幫助你構造出更好、更高效的查詢。
不要強制SQL Server每次執行查詢的時候重新編譯和構造查詢執行計劃。避免這種重復操作的一種簡單方法是使用帶有參數的存儲過程。注意盡量不要使用ADO Command對象的Prepare屬性——有時它不能正確工作。如果使用存儲過程,你還可以通過消除不必要的「受影響行數」返回值進一步提高ADO性能——只需在存儲過程中加入SET NOCOUNT ON就可以了。
盡量減少與伺服器的通信次數。如果你有幾個相關的操作要執行,請把它們合並為一個存儲過程,或者是一個可以在伺服器上作為腳本執行的復合查詢。避免使用方法(比如Refresh)和不適當的Parameters集合引用,它們會強制ADO增加額外的伺服器通信過程。
在客戶機/伺服器應用中,只構造Command對象一次,而不是每次使用Command對象的時候重新構造。你可以重新設置Command的參數值,然後在需要時執行它。
當查詢返回的不是一個記錄集時,確保使用了adExecuteNoRecords選項,告訴ADO越過所有那些用來接收和構造記錄集(Recordset格式)的代碼。你可以把adExecuteNoRecords選項傳遞給Execute方法,或把它作為Command的選項。
執行返回簡單記錄集的存儲過程時,不要使用Command對象。所有的存儲過程(以及Command對象)可以作為Connection對象的COM方法出現。讓存儲過程作為Connection對象的方法出現有著顯著的性能優勢,同時它也簡化了代碼。盡管這種技術對於那些有Return Status值或Output參數的存儲過程沒有什麼幫助,但對於動作查詢(INSERT、DELETE等)以及那些返回一個或多個記錄的查詢來說,這種技術很有用。把存儲過程作為Connection的方法之後,你可以用方法參數的形式傳入存儲過程的輸入參數;如果調用存儲過程返回了一個記錄集,你可以通過方法調用中最後一個參數引用該Recordset。例如,下面的ADO語句執行一個名為「Fred」的存儲過程,Fred存儲過程有兩個輸入參數,返回一個Recordset:
MyConnection.Fred "InputArg1", 2, myRecordset
編寫代碼的時候,不要寄希望於VB的自動完成功能會把存儲過程或Command對象名字視為合法的Connection對象的方法。在正式運行之前,COM不會解析這類名字。
除非絕對必要,否則不要返回記錄集。當正在執行的查詢返回記錄時,ADO就會構造一個Recordset對象。構造Recordset對象的開銷很大,因此你應該盡量避免使用Recordset對象。注意有時候執行查詢雖然返回結果,但不是返回記錄。例如,你可以通過Return Status參數返回整數值。另外,你可以返回Output參數來替代需要構造Recordset對象的記錄集,SQL Server允許返回的Output參數多達1000個。
只要有可能,請用動作查詢(INSERT,UPDATE,DELETE和執行這些操作的存儲過程)替代可更新的Recordset游標。此時,你應該使用Execute方法和它的adExecuteNoRecords選項,確保ADO能夠知道查詢不需要構造Recordset對象。
除非必要,否則不要請求伺服器進行排序。大多數情況下,對於一個適度大小的Recordset對象,當它被發送到客戶端之後,排序速度將更快。另外,如果讓ADO客戶程序排序Recordset中的記錄,則客戶應用程序能夠按照用戶選擇的次序排序,從而提高了靈活性。
在編寫查詢之前了解索引的結構。創建合適的索引,調整查詢的語法以利用這些索引,你將能夠提高記錄提取的速度。Query Analyzer能夠幫助你決定是否有必要添加更多的索引。
不要一次性返回太多的記錄。很多時候,容量太大的記錄集會嚴重地影響應用程序的性能。只返回那些當前你需要的記錄,如果客戶程序需要更多的記錄,則以後隨時提取。通過帶有參數的WHERE子句,或者靈活地運用TOP N查詢,限制查詢的范圍。
不要返回太多的列。避免使用SELECT *。SELECT *語句告訴SQL Server返回所有的列,不管實際存在的列有多少。只選擇那些你需要的列,這樣,當有人為表增加了更多的列時,你不會得到大得出奇的結果集。
避免使用游標。如果你必須使用游標,那麼不要使用那些所需資源數量超過必要的游標類型。如果沒有必要,不要要求游標提供滾動、更新和數據緩沖能力。
詳細地告訴ADO你想要它做些什麼。打開Recordset或者構造Command對象時,不要忘了設置CommandType選項。它避免了ADO「猜測」你的意圖,你將能夠減少與伺服器的通信,而且使得代碼更加穩定。
另外,學習使用診斷工具,測定運行在伺服器上的代碼和應用程序的代碼佔用了多少時間——以及這些時間花在哪裡。在這方面,SQL Server Profiler是一個寶貴的工具。它能夠闡明你的代碼在要求伺服器做些什麼,能夠在草率構造的查詢中或對於錯誤選擇的命令屬性突出顯示。另外,Query Analyzer還能夠用圖示的方式顯示出SQL Server將如何執行查詢,提出改進查詢的建議,幫助你調整查詢。Query Analyzer甚至還能夠執行它提出的建議(例如,添加或者刪除索引),你只需點擊一下按鈕就可以完成。
四、處理查詢結果
查詢結果記錄發送到客戶端之後,客戶端應用程序可能需要相當可觀的時間去處理結果集。每一種體系(客戶機/伺服器,多層體系中的中間層,以及ASP)都為優化這個階段的代碼提供了相應的技術。下面是幾個能夠顯著改善性能的技巧。
我在代碼中看到最多的錯誤之一是:在引用Recordset Field.Value的時候,使用延遲綁定(Late Binding)。由於代碼需要頻繁地引用Value屬性,而且通常要引用的Field對象有很多,本文前面提到的倍數因子將起到重要影響——因此,所有這里介紹的技巧能夠顯著地改善性能。一些開發者使用延遲綁定技術的原因在於,他們想要明確地標識出SELECT語句選擇了哪些行。為了這個目標,許多人使用了用引號包圍字元串的做法。例如,為了引用記錄集RS欄位集合中的「Cows」欄位,你可能使用:
RS("Cows")或者:RS.Fields("Cows").Value
後面這種方法顯式地引用了記錄集內Fields集合中指定成員的Value屬性。這種方法要稍微快一點,而且當你把這些代碼向Visual Basic.NET遷移時,它的向上兼容性也要好一些。上述方法的一種變化是使用感嘆號(!)操作符:
RS!Cows
與先行綁定(Early-Binding)相比,採用上述方法時COM進行解析的時間要長得多,這是因為它們強制COM在運行時(而不是在編譯時)解析對Value屬性的引用,每一次對該對象的引用都要求有一系列類似的、後台進行的查找過程。
然而,使用延遲綁定時,不存在代碼引用的是哪一個列這類問題。如果你完全按照下列方式編寫代碼:
RS(0) ' 指向第一個列(Fields集合的成員)
這時,COM能夠在編譯時解析Value屬性地址,代碼的運行速度將加快。但是,只有那些了解查詢所返回的列以及返回次序的人能夠理解這行代碼到底指向了哪一個列。如果開發者不具備控制查詢數據源的許可權(這是很常見的情況),這種方法可能帶來問題。為了確定RS(0)引用了哪一個SELECT列,你必須找出生成該Recordset的是哪一個SELECT語句、搞清楚SELECT語句所返回的各個列。
然而,有幾種技術允許你既能夠實現快速地運行時引用,同時保證代碼的可讀性。其中一種方法的要求如下:開發者必須創建一個查詢所返回列的枚舉列表。如果查詢被改變,比如返回更多的列,或者列的次序發生變化,開發者必須修改和重新部署枚舉列表。遺憾的是,要保持枚舉列表與查詢的匹配,對於管理者來說是一個有些困難的任務。例如,為了快速、明白地標識出ADO代碼引用的是哪一個列,你可以結合下面的SELECT語句和枚舉列表:
SELECT CatName, CatType, CatSize from Cats Where...Enum enuCatsQuery CatName CatType CatSizeEnd Enum
注意,SELECT語句返回的列與枚舉列表中聲明的列完全匹配。此後,當你需要引用Recordset的Fields集合時,可以使用下面的代碼:
StrMyName = Rs(enuCatsQuery.CatName)
按照這種方法,代碼不僅具有較好的可讀性,而且它仍舊是編譯時綁定,代碼的運行速度明顯加快。
然而,要避免延遲綁定,你還可以使用另外一種方法。[email protected]列表服務上一場長時間的討論得出了一種我稱之為預先綁定(Prebinding)的方法,它結合了兩種技術。當你只需引用Field對象一次時,這種技術沒有什麼幫助;但在客戶機/伺服器應用中,預先綁定方法非常理想。使用這種方法時,你要創建多個獨立的、命名的Field對象,並把這些對象設置為Recordset對象Fields集合中的成員。編寫代碼的時候,你首先要為每一個想要使用的欄位創建一個命名的Field對象,例如:
Dim fldName as ADODB.FieldDim fldType as ADODB.FieldDim fldSize as ADODB.Field
創建這些Field對象需要一定的開銷。然而,你應該估量一下,這是一次性的開銷,但它卻能夠戲劇性地改善性能。
打開Recordset之後,你只需一次性地把這些命名的Field對象設置為SELECT查詢選擇出來的列:
If fldName is Nothing thenSet fldName = RS!CatNameSet fldType = RS!CatTypeSet fldSize = RS!CatSizeEnd if
你可以在這里用引號包圍字元串的方法引用列,甚至也可以使用感嘆號操作符。由於這里的代碼只運行一次,不論使用什麼方法,性能的差異都不大。接下來,當你需要引用Field對象(查詢之後)時,只需使用預先綁定的變數即可:
strName = fldNamestrType = fldTypestrSize = fldSize
這種預先綁定方法的性能甚至比序數引用方式(例如RS(0))都要好。
五、客戶機/伺服器、中間層和ASP策略
在編寫代碼的時候,你還必須考慮到其他一些影響性能的因素。其中一些因素與ADO沒有什麼關系——它們與COM有關。Microsoft最近的一份白皮書指出,在Windows 2000 ASP頁面中執行ADO操作(連接,查詢,處理)要比調用COM組件執行同樣的代碼更快。這個結論並不令人奇怪:當我們從VB調用一個外部COM組件(處於當前進程之外的一些代碼),訪問COM組件以及把控制傳遞給它時在後台進行的操作復雜得出奇,而且速度很慢。雖然我們沒有必要刻意避免調用COM組件去運行ADO代碼。但是,我們不應該簡單地把多個獨立的ADO操作封裝成大量的小型COM組件,然後在需要的時候每次都去調用它們。相反,我們應該盡量把全部邏輯封裝到一個COM組件裡面,使得程序只需一次調用,COM就能夠完成大多數(如果不是全部)操作。我相信,你已經發現運行二進制形式的(例如COM組件)ADO代碼要比運行ASP之類的解釋執行代碼要快。因此,你應該尋找一些方法,減少進入COM組件和從COM組件返回所需要的昂貴開銷。
如果你離不開Command對象,或者不能預先綁定Field對象並在必要時重用,那麼你應該考慮避免多餘的對象創建操作的技術。在這種情況下,把存儲過程作為Connection對象的方法調用有著更重要的意義。另外,用先行綁定的方式引用Field屬性也有助於改善性能。記住操作完成後必須進行的清理工作:關閉Connection和Recordset對象,然後把它們設置成Nothing。
為了讓代碼和代碼編寫者都表現出最好的性能,請記住以下基本規則:利用連接池和非同步連接;減少ADO代碼和資料庫伺服器通信的次數;選用一種COM-先行綁定技術;除非必要,盡量避免使用代價昂貴的ADO對象,例如Recordset和Command對象;如有可能,用Return Status和Output參數替代記錄集。盡可能地提高查詢的效率,如有可能,不要忘了利用存儲過程。詳細地告訴ADO你想要它做些什麼,避免讓ADO猜測你的意圖——顯式地指定ADO CommandType,使用adExecuteNoRecords之類的選項。
對於本文所介紹的所有技巧和其他文章提出的編程忠告,我建議你以審視的目光看待它們。我們所做的工作、所編寫的代碼、所構造的系統,都屬於非常復雜的東西,許多不斷變化的因素影響著它們。理解了這一點之後,如果你對本文所討論的某一項技術感興趣,可以先進行一下試驗。如果它確實有效,那麼就正式實現它,然後再進行測試。如果這時它仍舊有效,那麼恭喜你。如果它不再有效,你得看看是否違反了應用該技術的必要條件。
㈢ 使用VB+ADO設計與開發一個簡單的資料庫應用系統(資料庫採用 SQL Server),編個小程序。
資料庫的
要求是什麼。
任務是
㈣ 使用VB+ADO設計與開發一個簡單(綜合)的資料庫應用系統(資料庫採用 SQL Server)
到codefans上vb 資料庫中
㈤ C++ :ADO實現數據訪問層的封裝 實現對資料庫的修改時 。。。
允許開發人員編寫訪問數據的代碼而不用關心資料庫是如何實現的,而只用關心到ADO向我們提供了一個熟悉的,高層的對OLE DB的Automation封裝介面。對那些
㈥ ado封裝描述
一、前言
用過ADO的人都知道, 調用ADO要處理很多"麻煩"的事情,如異常處理等,要寫很多try - catch塊. 有點不甚其煩。我乾脆把常用的函數都封裝起來,免去老是要寫try - catch塊的麻煩。做起來雖然沒有什麼技術含量,但也比較煩瑣,所以只完成了一部分,且由於時間及個人水平有限,沒有對封裝的東西作全面測試,並必定有很多錯誤,但想到對某些朋友可能有用。所以先"捐"出來了。^-^.
在介紹這兩個類之前,讓我們先來了解一下ADO,本文假設你已有一定的編程能力:
二、了解ADO的結構體系
ADO(ActiveX Data Object, Active 數據對象)是Microsoft提供的一種面向對象,與語言無關的數據訪問應用編程介面。據大部分資料介紹,它有如下主要特點:
一:易於使用。
二:可以訪問多種數據源。
三:訪問速度快,效率高:
四:方便Web應用。
五:技術編程介面豐富。
六:低內存支出和佔用磁碟空間較少.
正是看到ADO這么多優點,使我對用ADO開發資料庫產生了興趣.ADO用起來也如前面所說的一樣,確實不難。總的來說,ADO模型包括了下列對象:連接(Connection)、命令 (Command)、記錄集 (Recordset)、欄位 (Field)、參數 (Parameter)、錯誤 (Error)、屬性 (Property)、集合 、事件.它們之間的關系如下圖:
(1)我們最常用的主要是Connection、Recordset及Command這三個對象.
(2)對於訪問一個資料庫來說,我們一般先建立一個ADO連接.
(3)ADO連接可以直接執行SQL語句來操縱資料庫,但如果我們要對數據在應用程序和數據源之間進行存取的話,就需要用到記錄集對象。一個ADO連接可以有多個ADO連接,但一個ADO連接一般只能對應一個且必須對應一個ADO連接.
(4)另外如果你可進行更高級別的訪問的話,還可能要用到命令對象。例如要調用存儲過程等。
(5)一個記錄集包含有一個欄位集,一個欄位集則包含有多個欄位對象。
(6)同樣一個命令對象也包含一個參數集,一個參數集則包含有多個參數對象。
(7)連接對象也有一個錯誤集並包含有多個錯誤對象。
這就是ADO各對象之間大致的關系.
三、了解ADO連接
在使用資料庫之前,要先建立連接.一般先用CreateInstance方法創建ADO連接對象,然後就可以用Open方法連接到資料庫。它的原型是 Open(BSTR ConnectionString, BSTR UserID, BSTR Password, long Options);其中UserID和Password如果在ConnectionString已經指明了用戶名和密碼,一般就可以不必管它們.Options指的是是以同步方式(adConnectUnspecified)還是以非同步方式(adAsyncConnect)進行連接,默認為同步.這個函數的關鍵這處在於ConnectionString參數,它決定了我們將以什麼方式連接到什麼數據源,例如:
如果是Access資料庫,它的格式則一般為: "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=db.mdb";
如果是SQL Server: "Provider=SQLOLEDB.1;Data Source=sqlservername;Initial Catalog=master;UserID=sa; PWD=password";
具體的內容視你的環境而定.要連接到其他資料庫,請參考相關的資料.
例如:
_ConnectionPtr pConnection;
LPCSTR strConnect = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=test.mdb";
//創建 Connection 對象---------------------------
HRESULT hr = pConnection.CreateInstance("ADODB.Connection");
//設置連接時間-----------------------------------
pConnection->put_ConnectionTimeout(long(5));
if (SUCCEEDED(hr))
{
// 連接資料庫---------------------------------------------
pConnection->Open(strConnect, "", "", adConnectUnspecified))
}
四、了解ADO記錄集
創建了ADO連接,我們就可以通過ADO記錄集來訪問資料庫了.同樣,在使用記錄集之前要先創建對象.然後調用Open方法打開記錄集.它不但可以執行普通的SQL語句,還可以調用存儲過程等等:
Open(VARIANT Source, VARIANT ActiveConnection, CursorTypeEnum CursorType,LockTypeEnum LockType, LONG Options).
其中ActiveConnection參數為一個有效的 Connection 對象名,就是我們在上面所說過的ADO連接對象.
CursorType參數指的是記錄集游標類型,在官方的資料中是這樣說明它的取值類型的:
1.adOpenForwardOnly 僅向前游標,默認值。除了只能在記錄中向前滾動外,與靜態游標相同。當只需要在記錄集中單向移動時,使用它可提高性能。
2.adOpenKeyset 鍵集游標。盡管從您的記錄集不能訪問其他用戶刪除的記錄,但除無法查看其他用戶添加的記錄外,鍵集游標與動態游標相似。仍然可以看見其他用戶更改的數據。
3.adOpenDynamic 動態游標。可以看見其他用戶所作的添加、更改和刪除。允許在記錄集中進行所有類型的移動,但不包括提供者不支持的書簽操作。
4.adOpenStatic 靜態游標。可以用來查找數據或生成報告的記錄集合的靜態副本。另外,對其他用戶所作的添加、更改或刪除不可見。
我們現在可不用管這么多,就用默認的adOpenStatic類型吧.
LockType參數,用於指示在什麼時候鎖定記錄:
AdLockReadOnly (默認值)只讀 - 不能改變數據。
AdLockPessimistic 保守式鎖定(逐個) - 提供者完成確保成功編輯記錄所需的工作,通常通過在編輯時立即鎖定數據源的記錄。
AdLockOptimistic 開放式鎖定(逐個) - 提供者使用開放式鎖定,只在調用Update 方法時才鎖定記錄。
AdLockBatchOptimistic 開放式批更新-用於批更新模式(與立即更新模式相對)。
Options參數指的是操作類型:
adCmdText 指示strSQL為命令文本, 即普通的SQL語句.
adCmdTable 指示ADO生成SQL查詢以便從在strSQL中命名的表中返回所有行.
adCmdTableDirect 指示所作的更改在strSQL中命名的表中返回所有行.
adCmdStoredProc 指示strSQL為存儲過程.
adCmdUnknown 指示strSQL參數中的命令類型為未知
adCmdFile 指示應從在strSQL中命名的文件中恢復保留(保存的)Recordset.
adAsyncExecute 指示應非同步執行strSQL.
adAsyncFetch 指示在提取 Initial Fetch Size 屬性中指定的初始數量後,應該非同步提取所有剩餘的行.如果所需的行尚未提取,主要的線程將被堵塞直到行重新可用.
adAsyncFetchNonBlocking 指示主要線程在提取期間從未堵塞. 如果所請求的行尚未提取,當前行自動移到文件末尾.
唉又是一大串,如果你只是要執行SQL語句,就把它設為adCmdText吧. 這樣Source就是你要執行的SQL語句了.
例如:
LPCSTR strSQL = "select * from vckbasetable";
_RecordsetPtr pRecordset;
pRecordset.CreateInstance("ADODB.Recordset");
pRecordset->Open(_bstr_t(strSQL),
_variant_t((IDispatch*)pConnection, true),
adOpenStatic,
AdLockOptimistic ,
adCmdText);
ADO中讀取記錄集中指定欄位的值一般有兩種方法:
第一種:
FieldsPtr pFields;
pRecordset->get_Fields(&pFields);
pFields->Item[L"COLUMN_NAME"]->Value;
//或pFields->Item[long(index)]->Value;
//其中index為整型或長整型.GetFields()函數返回的是記錄集對象的欄位集合對象的指針.
第二種:
pRecordset->get_Collect("COLUMN_NAME");
//或pRecordset->get_Collect(long(index));
它們都將返回一個_variant_t類型的值,推薦使用後一種方法.
例如:
int ncol = rset.GetFieldsCount();
while (!rset.IsEOF())
{
for (int i = 0; i < ncol; i++)
{
rset.GetValueString(value, (long)(i));
}
rset.MoveNext();
}
四、了解ADO欄位.
一個記錄集通常包含多個欄位,通過訪問記錄,我們可以得到很多有用的信息,如欄位名,欄位的數據類型,定義的寬度,實際佔有的寬度等等:
一般用記錄集的get_Fields方法取得欄位集合對象:
FieldsPtr pFields;
Recordset->get_Fields(&pFields);
然後可以獲得相應的欄位對象:
long lIndex = 0;
FieldPtr pf = pFields->GetItem(_variant_t(lIndex));
//或: FieldPtr pf = pFields->GetItem("COLUMN_NAME");
欄位對象有很多有用的屬性,這些可以參考我的源代碼或其他相關資料.如:
get_ActualSize(long *pl) //實際寬度
get_Attributes(long *pl) //屬性
get_DefinedSize(long *pl) //定義寬度(以位元組為單位,如整型為4,長整型為8...)
get_Name(BSTR *pbstr) //欄位名
get_Type(DataTypeEnum *pDataType) //數據類型
get_Value(VARIANT *pvar) // 欄位的值
有了以上對ADO的基本了解後,我們將正式開始編寫應用程序,請看下文。
使用ADO封裝類的資料庫程序開發實例(下)
type=text/javascript>
最新評論 [發表評論] [文章投稿] 查看所有評論 推薦給好友 列印
高手啊,問個問題,比較急!
怎麼能夠同步查詢資料庫中的數據呢?
麻煩點也沒什麼! ( sunshinesky 發表於 2005-5-31 18:21:00)
有些類我還是不清楚在本例子中有什麼作用,能講清楚點嗎?謝謝! ( keystone 發表於 2004-8-6 11:42:00)
偉大 ( kl334 發表於 2004-7-31 18:24:00)
代碼已經更新,修復了幾個嚴重的bugs. ( vckbase 發表於 2003-4-9 0:40:00)
不錯,方便了不少。例子中
CAccessView::UpdateGrid()對寬度的計算稍有不妥。
如下
int nwidth = rset.GetFieldDefineSize(i) * 200;
nwidth = nwidth > 2009 ? 2009 : nwidth;
當是memo欄位時結果大於int型最大限制。結果nwidth為負數。
可改為
nwidth = (nwidth > 2009||nwidth < 0) ? 2009 : nwidth;
( sambatree 發表於 2003-3-26 14:26:00)
㈦ 關於ADO封裝的問題!急。
一個常用的對數據層訪問的模式為DAO(data access object)
將所有與資料庫相關的代碼(如:sql, recordset , connection等)都封裝到類中,系統中要用到資料庫操作的地方就調用 類.
至於類如何分類分,有2種基本的方法:
1.所有資料庫相關的代碼放到一個類中,這種方法會使類非常龐大,不建議使用
2.一個表一個類,例如資料庫中有個STUDENT表,我們寫一個StudentDao類,其中包括對STUDENT表的所有操作,如包括insert(), delete(), search(),update()等函數,這些函數中就放資料庫操作的相關代碼.這種方法很常用.
㈧ MFC下開發的程序,使用ado方法連接SQL SERVER資料庫的那段連接代碼 跪求啊。。。。
首先確認你的用戶名和密碼正確和資料庫伺服器默認實例已經正常啟動;然後你試試下面的連接字_bstr_t strConnect="Provider=SQLOLEDB.1;DataSource=(local);InitialCatalog=StuDB; User ID="sa";Password="sa";連接本地資料庫伺服器默認實例有三種方式:(local)、LocalHost、127.0.0.1。所以,local要加括弧或者改用LocalHost;還有你的初始編目中是指定資料庫名稱而不是資料庫文件的名稱,所以StuDB_Data.MDF改為StuDB(請確認你建立的資料庫名稱為StuDB)。然後你再試一試,如果還不行,請將錯誤貼上!
㈨ 求在visual studio 環境中用VC++ 實現一個小工程,並用ADO連接資料庫。
生成應用程序框架並初始化OLE/COM庫環境
創建一個標準的MFC AppWizard(exe)應用程序,然後在使用ADO資料庫的InitInstance函數中初始化OLE/COM庫(因為ADO庫是一個COM DLL庫)。
本例為:
BOOL CAdotestDlg::OnInitDialog()
{
::CoInitialize(NULL); //初始化OLE/COM庫環境
}
程序最後要調用 ::CoUninitialize();//釋放程序佔用的COM 資源。
另外:
m_pRecordset->Close(); 注意!!!不要多次關閉!!!!!!!!!!!!
m_pConnection->Close();
m_pRecordset = NULL;
m_pConnection = NULL;
2. 引入ADO庫文件
使用ADO前必須在工程的stdafx.h文件最後用直接引入符號#import引入ADO庫文件,以使編譯器能正確編譯。代碼如下:
#import "C:\Program Files\common files\system\ado\msado15.dll" no_namespace rename("EOF","adoEOF")
ADO類的定義是作為一種資源存儲在ADO DLL(msado15.dll)中,在其內部稱為類型庫。類型庫描述了自治介面,以及C++使用的COM vtable介面。當使用#import指令時,在運行時Visual C++需要從ADO DLL中讀取這個類型庫,並以此創建一組C++頭文件。這些頭文件具有.tli 和.tlh擴展名,讀者可以在項目的目錄下找到這兩個文件。在C++程序代碼中調用的ADO類要在這些文件中定義。
程序的第三行指示ADO對象不使用名稱空間。在有些應用程序中,由於應用程序中的對象與ADO中的對象之間可能會出現命名沖突,所以有必要使用名稱空間。如果要使用名稱空間,則可把第三行程序修改為: rename_namespace("AdoNS")。第四行代碼將ADO中的EOF(文件結束)更名為adoEOF,以避免與定義了自己的EOF的其他庫沖突。
3.利用智能指針進行資料庫操作
在CaboutDlg頭文件中定義兩個ADO智能指針類實例,並在對話框中加入一個ListCtrl。
class CAdotestDlg : public CDialog
{
_ConnectionPtr m_pConnection;
_RecordsetPtr m_pRecordset;
ClistCtrl m_List;
......
}
ADO庫包含三個智能指針:_ConnectionPtr、_CommandPtr和_RecordsetPtr。
_ConnectionPtr通常被用來創建一個數據連接或執行一條不返回任何結果的SQL語句,如一個存儲過程。
_CommandPtr返回一個記錄集。它提供了一種簡單的方法來執行返回記錄集的存儲過程和SQL語句。在使用_CommandPtr介面時,可以利用全局_ConnectionPtr介面,也可以在_CommandPtr介面里直接使用連接串。 _RecordsetPtr是一個記錄集對象。與以上兩種對象相比,它對記錄集提供了更多的控制功能,如記錄鎖定、游標控制等。
在使用ADO程序的事件響應中OnButton1加入以下代碼:
void CAdotestDlg::OnButton1()
{
m_List.ResetContent();
m_pConnection.CreateInstance(_uuidof(Connection)); //初始化Connection指針
m_pRecordset.CreateInstance(_uuidof(Recordset));//初始化Recordset指針
try
{
m_pConnection->Open("DSN=ADOTest","","",0); //連接叫作ADOTest的ODBC數據源
//注意:這是連接不需要用戶ID或密碼的open 函數
// 否則形式為 ->Open("DSN=test;uid=sa;pwd=123;","","",0);
// 執行SQL語句得到一個記錄集把其指針賦值給m_pRecordset
CString strSql="select * from middle";
BSTR bstrSQL = strSql.AllocSysString();
m_pRecordset->Open(bstrSQL,(IDispatch*)m_pConnection,adOpenDynamic,adLockOptimistic,adCmdText);
//adOpenDynamic:動態 adLockOptimistic樂觀封鎖法 adCmdText:文本查詢語句
while(!m_pRecordset->adoEOF)//遍歷所有記錄
{
//取紀錄欄位值方式之一
_variant_t TheValue; //VARIANT數據類型
TheValue = m_pRecordset->GetCollect("BIG_NAME");//得到欄位BIG_NAME的值
if(TheValue.vt!=VT_NULL)
m_List.AddString((char*)_bstr_t(TheValue));
//將該值加入到列表控制項中
//取紀錄欄位值方式之二
// _bstr_t TheValue1=m_pRecordset->Fields->GetItem("BIG_NAME")->Value;
// CString temp=TheValue1.();
// m_List.AddString(temp);
//數據類型轉換
_variant_t vUsername,vBirthday,vID,vOld;
TRACE("id:%d,姓名:%s,年齡:%d,生日:%s\r\n",
vID.lVal,(LPCTSTR)(_bstr_t)vUsername,vOld.lVal,(LPCTSTR)(_bstr_t)vBirthday);
m_pRecordset->MoveNext();//轉到下一條紀錄
}
m_pRecordset->Close();
m_pConnection->Close();
}
catch (_com_error e)//異常處理
{
AfxMessageBox(e.ErrorMessage());
}
m_pRecordset->Close(); //注意!!!不要多次關閉!!!!否則會出錯
m_pConnection->Close();
m_pRecordset = NULL;
m_pConnection = NULL;
}
程序中通過_variant_t和_bstr_t轉換COM對象和C++類型的數據, _variant_t類封裝了OLE自治VARIANT數據類型。在C++中使用_variant_t類要比直接使用VARIANT數據類型容易得多。
好,編譯後該程序就能運行了,但記住運行前要創建一個叫ADOTest的ODBC數據源。該程序將把表middle中的BIG_NAME欄位值顯示在列表控制項中。
㈩ 怎麼在VC++中用ADO創建資料庫
VC++中使用ADO方式操作ACCESS資料庫是Microsoft資料庫應用程序開發的新介面,是建立在OLEDB之上的高層資料庫訪問技術,即使你對OLEDB,COM不了解也能輕松對付ADO,因為它非常簡單易用,甚至比你以往所接觸的ODBCAPI、DAO、RDO都要容易使用,並不失靈活性。本文詳細地介紹在VisualC++開發環境下如何使用ADO來進行資料庫應用程序開發,並給出示例代碼。為了使讀者朋友都能測試本例提供的代碼,我們採用Access資料庫,您可以直接在我們提供的示例代碼中找到這個test。mdb。程序編譯運行後的效果一所示:
一、實現方法
萬事開頭難,任何一種新技術對於初學者來說最重要的還是"入門",掌握其要點。讓我們來看看ADO資料庫開發的基本流程吧!它的基本步驟如下:
(1)初始化COM庫,引入ADO庫定義文件
(2)用Connection對象連接資料庫
(3)利用建立好的連接,通過Connection、Command對象執行SQL命令,或利用Recordset對象取得結果記錄集進行查詢、處理。
(4)使用完畢後關閉連接釋放對象。
下面我們將詳細介紹上述步驟並給出相關代碼。
1、COM庫的初始化
我們可以使用AfxOleInit()來初始化COM庫,這項工作通常在CWinApp::InitInstance()的重載函數中完成,請看如下代碼:
BOOLCADOTest1App::InitInstance()
{
AfxOleInit();
。。。。。。
}
2、用#import指令引入ADO類型庫
為了引入ADO類型庫,需要在項目的stdafx。h文件中加入如下語句:
#import"c:\programfiles\commonfiles\system\ado\msado15。dll"
no_namespacerename("EOF","adoEOF")
這一語句有何作用呢?其最終作用同我們已經十分熟悉的#include類似,編譯的時候系統會為我們生成msado15。tlh,ado15。tli兩個C++頭文件來定義ADO庫。
需要讀者朋友注意的是:您的開發環境中msado15。dll不一定在這個目錄下,請按實際情況修改;在編譯的時候可能會出現如下警告,對此微軟在MSDN中作了說明,並建議我們不要理會這個警告:msado15。tlh(405):warningC4146:,resultstillunsigned。
3、創建Connection對象並連接資料庫
為了首先我們需要添加一個指向Connection對象的指針_ConnectionPtrm_pConnection,下面的代碼演示了如何創建Connection對象實例及如何連接資料庫並進行異常捕捉:
BOOLCADOTest1Dlg::OnInitDialog()
{
CDialog::OnInitDialog();
HRESULThr;
try
{
hr=m_pConnection。CreateInstance("ADODB。Connection");///創建Connection對象
if(SUCCEEDED(hr))
{
hr=m_pConnection->Open("Provider=Microsoft。Jet。OLEDB。4。0;
DataSource=test。mdb","","",adModeUnknown);///連接資料庫
//上面一句中連接字串中的Provider是針對ACCESS2000環境的,對於ACCESS97,
//需要改為:Provider=Microsoft。Jet。OLEDB。3。51;
}
}
catch(_com_errore)///捕捉異常
{
CStringerrormessage;
errormessage。Format("連接資料庫失敗!\r\n錯誤信息:%s",e。ErrorMessage());
AfxMessageBox(errormessage);///顯示錯誤信息
}
在這段代碼中我們是通過Connection對象的Open方法來進行連接資料庫的,下面是該方法的原型:
HRESULTConnection15::Open(_bstr_tConnectionString,_bstr_tUserID,_bstr_tPassword,longOptions);
上述函數中參數ConnectionString為連接字串;參數UserID是用戶名;參數Password是登陸密碼;參數Options是連接選項,用於指定Connection對象對數據的更新許可權,一般情況下Options可以是如下幾個常量:
adModeUnknown:預設。當前的許可權未設置