日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ADO

發布時間:2025/4/16 编程问答 13 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ADO 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

1 基礎????1

1.1 引入ADO庫文件????1

1.1.1 版本????1

1.2 初始化OLE/COM庫環境????2

1.3 comdef.h????2

1.3.1 字符串編碼轉換????2

1.3.2 重要的類????3

1.3.3 重要的變量????4

1.3.4 智能指針????4

2 _ConnectionPtr????5

2.1 連接數據庫????5

2.2 執行SQL語句????5

2.3 事務處理????6

2.4 斷開連接????7

3 _RecordsetPtr????8

3.1 打開記錄集????8

3.1.1 CursorLocation????9

3.1.2 CursorType????9

3.1.3 LockType????10

3.2 遍歷記錄集????11

3.3 關閉記錄集????12

3.4 訪問BLOB????12

3.4.1 寫入????12

3.4.2 讀取????14

3.4.3 更新????15

3.5 書簽????15

3.6 過濾????16

3.7 Find????16

3.8 Sort????17

3.9 Index????17

3.10 綁定數據????18

3.10.1 CADORecordBinding派生類????18

3.10.2 綁定????20

3.10.3 讀取字段????20

3.10.4 添加新記錄????21

4 _CommandPtr????23

4.1 執行SQL語句????23

4.1.1 無名參數????23

4.1.2 有名參數????23

4.2 修改BLOB????24

4.3 執行存儲過程????24

4.3.1 無名參數????25

4.3.2 有名參數????26

4.3.3 Refresh????27

4.3.4 游標位置????27

4.4 重復使用命令對象????28

5 ADOX????29

5.1 引入庫文件????29

5.1.1 一個BUG????29

5.2 創建數據庫????30

5.3 創建數據表????30

6 JRO????31

6.1 VB6.0????31

6.1.1 引用????31

6.1.2 代碼????31

6.2 VC++????32

6.2.1 引入????32

6.2.2 代碼????32

7 常見問題????33

7.1 連接失敗的原因????33

7.2 改變當前數據庫????33

7.3 判斷某個數據庫是否存在????33

7.4 判斷某個表是否存在????34

7.5 ADO鎖定整張表????34

7.6 獲取記錄集行數????35

7.7 解決并發沖突????35

?

?

1 基礎

1.1 引入ADO庫文件

VC++使用ADO,首先需要導入ADO的類型庫。可以在StdAfx.h里增加如下代碼:

#import "c:/program files/common files/system/ado/msado15.dll" no_namespace rename("EOF","adoEOF")

no_namespace表示不需要命名空間。刪除這個詞,則ADO的接口函數將被放在ADODB命名空間內。也可以用rename_namespace("ADO")將命名空間更改為ADO

rename("EOF","adoEOF")表示將EOF更改為adoEOF。因為EOF在某些文件里被定義為(-1),如此一來,VARIANT_BOOL EOF;就變成了VARIANT_BOOL (-1);把它當做類成員變量編譯時就會出錯。

VC++編譯器中的預處理器針對這條指令做了哪些工作呢?

1、根據msado15.dll里的類型庫信息生成COM組件的接口文件。具體的就是生成msado15.tlhmsado15.tli,前者是聲明文件,后者是實現文件;

2、替換#import語句為#include "msado15.tlh"。這樣,源文件里就可以使用COM組件的接口了;

3msado15.tliCOM接口的實現文件,如果沒有它則程序可以編譯但無法連接。不過,msado15.tlimsado15.tlh包含起來了(通過#pragma start_map_region#include),且它的函數全部為內聯的。因此,不用再單獨編譯msado15.tli

1.1.1 版本

Windows7 sp1里的msado15.dll,其類型庫版本為 6.1,而Windows XPmsado15.dll的版本為2.x。最關鍵的是新版本的類型庫并不是向下兼容的!

如果在Windows7下編譯代碼,然后在Windows XP下運行,就有可能會出現問題。解決方法有兩個:

1#import "msado15.dll"中的msado15.dll請使用低版本的,即Windows XP里的msado15.dll

2、升級Windows XP里的ADO組件。

1.2 初始化OLE/COM庫環境

ADO是一組COM動態庫,所以使用ADO前,必須初始化OLE/COM庫。在MFC應用程序里,一個比較好的方法是在應用程序主類的InitInstance成員函數里初始化OLE/COM庫。

BOOL CMyAdoTestApp::InitInstance()

{

AfxOleInit();????//這就是初始化COM

……

}

也可以使用 CoInitializeCoInitializeExOleInitialize初始化COM庫,退出程序前請使用CoUninitializeOleUninitialize

1.3 comdef.h

msado15.tlh文件里,語句#include <comdef.h>包含了comdef.h頭文件,這個頭文件里又有如下語句:

... ... ...

#include <comutil.h>

... ... ...

#pragma comment(lib, "comsupp.lib")

comdef.hcomutil.hcomsupp.lib包含了一些重要的變量、函數、類。

1.3.1 字符串編碼轉換

comutil.h頭文件里有兩個函數可用于字符串的編碼轉換:

namespace _com_util

{

BSTR __stdcall ConvertStringToBSTR(const char*pSrc);

char* __stdcall ConvertBSTRToString(BSTR pSrc);

}

_com_util::ConvertStringToBSTRAnsi字符串轉換為Unicode字符串,返回值記得要調用SysFreeString釋放內存;

_com_util::ConvertBSTRToString Unicode字符串轉換為Ansi字符串,返回值記得要調用 delete[] 釋放內存;

這兩個函數的實現代碼在comsupp.lib里。

1.3.2 重要的類

comutil.hcomdef.h這兩個頭文件里,有三個重要的類:_bstr_t_variant_t_com_error

_bstr_t 封裝了BSTR_variant_t封裝了VARIANT_com_error封裝了COM錯誤。

使用_bstr_t_variant_t可以極大的簡化代碼。以下面的代碼進行說明:

_RecordsetPtr m_pRecordset;

... ... ...

_variant_t vAge = m_pRecordset->GetCollect(_T("Age"));

上面的代碼用來讀取字段Age。查看msado15.tli里的Recordset15::GetCollect函數,可以知道COM組件返回的其實是一個VARIANTGetCollect函數返回前創建了一個臨時_variant_t對象,將VARIANT封裝了起來并返回給vAge

vAge析構時將調用VariantClear銷毀COM組件返回的VARIANT。如果Age字段是一個BSTR字符串,VariantClear會調用SysFreeString釋放BSTR字符串。

如果不借助_variant_t,而直接使用VARIANT,會是什么情況呢?那就是必須顯式的調用VariantClear函數,銷毀COM組件返回的每一個VARIANT。這樣代碼就會顯得非常臃腫,而且一旦疏忽就會發生內存泄露。

此外,使用_bstr_t也會相當的方便。

如:代碼_bstr_t s(m_pRecordset->GetCollect(_T("Age")));會自動將GetCollect返回的_variant_t轉換為BSTR字符串。

如:可以使用Ansi字符串構造_bstr_t對象

_bstr_t s1("測試_bstr_t");

如:可以使用Unicode字符串構造_bstr_t對象

_bstr_t s2(L"測試_bstr_t");

如:可以將Ansi字符串或Unicode字符串賦給_bstr_t變量

s1 = "_bstr_t測試";

s2 = L"_bstr_t測試";

如:可以輕松獲得Ansi字符串或Unicode字符串

const char*????????sA????=????(const char*)s1;????????????//返回Ansi字符串

const wchar_t*????sW????=????(const wchar_t*)s1;????????//返回Unicode字符串

需要注意的是:上面的sAsW所指向的內存由_bstr_t維護。_bstr_t對象s1析構時,sAsW也就成為了野指針。

1.3.3 重要的變量

comutil.h里,有全局變量vtMissing,其定義如下:

extern _variant_t vtMissing;

它其實是類型為VT_EMPTYVARIANT

1.3.4 智能指針

_COM_SMARTPTR_TYPEDEF用來聲明智能指針。

如:智能指針_ConnectionPtr的聲明如下:

_COM_SMARTPTR_TYPEDEF(_Connection, __uuidof(_Connection));

宏展開之后,其實就是:

typedef _com_ptr_t< _com_IIID<_Connection, &__uuidof(_Connection)> > _ConnectionPtr;

_ConnectionPtr的實質就是一個自動維護COM計數的_Connection

?

2 _ConnectionPtr

_ConnectionPtr表示與數據庫的連接。

2.1 連接數據庫

下面的代碼將實例化一個_ConnectionPtr,并連接數據庫

HRESULT hr = S_OK;

_ConnectionPtr m_pConnection;

{//創建連接

try

{

//創建 COM 對象,__uuidof(Connection) 可以替換為 "ADODB.Connection"

hr = m_pConnection.CreateInstance(__uuidof(Connection));

if(SUCCEEDED(hr))

{//連接 Access 數據庫 Demo.mdb

m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=Demo.mdb"

,"","",adModeUnknown);

}

}

catch(_com_error& e)

{

AfxMessageBox(e.Description());

}

}?

m_pConnection->Open用來連接數據庫。第一個參數用來指定連接字符串;第二、三個參數分別為用戶名和密碼;第四個參數是enum ConnectModeEnum,對數據庫的讀寫進行控制,如:adModeRead表示只讀……

2.2 執行SQL語句

Execute方法將執行SQL語句,其聲明如下:

_RecordsetPtr Connection15::Execute(_bstr_t CommandText

????????????????????????,VARIANT*RecordsAffected

????????????????????????,long Options);

CommandText????????是命令字串,通常是SQL命令

RecordsAffected????是操作完成后所影響的行數

Options????????????????表示CommandText的類型,取值如下

????????????????????adCmdText????????????表明CommandText是文本

????????????????????adCmdTable????????????表明CommandText是表名

????????????????????adCmdProc????????????表明CommandText是存儲過程

????????????????????adCmdUnknown????????未知

Execute執行完后返回一個記錄集。

示例代碼如下:

_variant_t RecordsAffected;

//執行SQL命令,創建表格

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);

//取得第一個字段的值放入vCount變量

_variant_t vCount = m_pRecordset->GetCollect((_variant_t)((long)0));

m_pRecordset->Close();//關閉記錄集

CString message;

message.Format("共有%d條記錄",vCount.lVal);

AfxMessageBox(message);///顯示當前記錄條數

2.3 事務處理

ADO中的事務處理也很簡單,只需分別在適當的位置調用Connection對象的三個方法即可,這三個方法是:

1、在事務開始時調用

pCnn->BeginTrans();

2、在事務結束并成功時調用

pCnn->CommitTrans();

3、在事務結束并失敗時調用

pCnn->RollbackTrans();

在使用事務處理時,應盡量減小事務的范圍,即減小從事務開始到結束(提交或回滾)之間的時間間隔,以便提高系統效率。需要時也可在調用BeginTrans()方法之前,先設置Connection對象的IsolationLevel屬性值,詳細內容參見MSDN中有關ADO的技術資料。

2.4 斷開連接

下面的代碼將斷開與數據庫的連接,并銷毀_ConnectionPtr實例

if(m_pConnection)

{//關閉ADO連接

if(m_pConnection->State)

{

m_pConnection->Close();

}

//下面的語句可有可無。因為m_pConnection是智能指針,析構時會自動Release

m_pConnection.Release();

}

?

3 _RecordsetPtr

_RecordsetPtr表示記錄集。

3.1 打開記錄集

使用Open方法打開記錄集,其聲明如下:

HRESULT Recordset15::Open(const _variant_t& Source

????????????????????????????,const _variant_t & ActiveConnection

????????????????????????????,enum CursorTypeEnum CursorType

????????????????????????????,enum LockTypeEnum LockType

????????????????????????????,long Options);

Source????????????????數據查詢字符串

ActiveConnection????_Connection*或連接數據庫的字符串

CursorType????????????光標類型

LockType????????????鎖定類型

Options????????????????可以取如下值之一:

????????????????????adCmdText????????????表明CommandText是文本命令

????????????????????adCmdTable????????????表明CommandText是表名

????????????????????adCmdProc????????????表明CommandText是存儲過程

????????????????????adCmdUnknown????????未知

下面的代碼首先實例化一個_RecordsetPtr,然后在_ConnectionPtr的基礎上,打開一個記錄集。注意Open函數的第二個參數,表示數據庫連接。

_RecordsetPtr m_pRecordset;

try

{

//創建 COM 對象,__uuidof(Recordset) 可以替換為 "ADODB.Recordset"

hr = m_pRecordset.CreateInstance(__uuidof(Recordset));

if(SUCCEEDED(hr))

{

m_pRecordset->CursorLocation = adUseClient;

m_pRecordset->Open(_T("SELECT * FROM DemoTable")

,m_pConnection.GetInterfacePtr()

,adOpenDynamic

,adLockOptimistic //樂觀鎖

,adCmdText);

}

}

catch(_com_error& e)

{

AfxMessageBox(e.Description());

}

可以將Open函數的第二個參數更換為連接字符串,如:"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=Demo.mdb"。在此情況下,Open函數首先連接數據庫,然后再打開一個記錄集。

3.1.1 CursorLocation

CursorLocation表示游標的位置,有兩個選項:

adUseServer????=????2????//默認,表示游標在服務端

adUseClient????????=????3????//表示游標在客戶端

游標在服務端,則記錄集對數據變化是敏感的。亦即當其它用戶修改了數據庫內的數據后,有可能會影響到客戶端已經打開的記錄集。游標在客戶端,就不會有數據敏感性了。

游標在服務端,則客戶端打開記錄集時數據將保留在服務端,不會通過網絡傳給客戶端。但是訪問記錄集里的數據時,就會頻繁的網絡通訊。游標在客戶端,則客戶端打開記錄集時數據將通過網絡緩存到客戶端。訪問記錄集里的數據時,將不再需要網絡通訊。因此,如果頻繁的訪問數據則客戶端游標的性能較高。

此外,服務端游標不支持書簽而客戶端游標支持書簽。這將影響到某些函數的使用,如:GetRecordCount函數有可能返回-1,而不是實際的記錄個數。

3.1.2 CursorType

游標類型有四種:

adOpenForwardOnly????????=????0,????//向前游標

adOpenKeyset????????????=????1,????//鍵集游標

adOpenDynamic????????=????2,????//動態游標

adOpenStatic????????????=????3????//靜態游標

adOpenForwardOnlyadOpenStatic 表示記錄集是靜態的:打開記錄集后,它就不會再發生變化,即使其他用戶修改了數據庫里的數據。兩者的區別在于adOpenForwardOnly只能向前移動游標,而adOpenStatic可以任意移動游標。

adOpenKeysetadOpenDynamic 表示記錄集是動態的:打開記錄集后,能夠反映其他用戶所做的修改。

adOpenKeyset 的實現原理:打開的記錄集僅僅保存記錄的關鍵字(Key),訪問某條記錄時是根據 Key 到數據庫訪問的。所以,其他用戶修改了某條記錄后,再訪問這條記錄,是能夠發現記錄改變了。但是,其他用戶如果增加、刪除記錄,并不會更改關鍵字記錄集,因此通過關鍵字記錄集,無法及時獲知增加、刪除的記錄。

adOpenDynamic 的實現原理:打開的記錄集會根據數據庫內容的變化及時予以更新。但是需要注意CursorLocation 必須等于 adUseServer,即游標必須在服務端才能實現此功能。

3.1.3 LockType

adLockReadOnly????????=????1,????????//只讀

adLockPessimistic????????=????2, ????????//悲觀鎖

adLockOptimistic????????=????3, ????????//樂觀鎖

adLockBatchOptimistic????=????4 ????????//批量樂觀鎖

悲觀鎖要求CursorLocation = adUseServer。它表示:編輯字段時就鎖定記錄,Update之后停止鎖定。這種方法最保險,但是效率最低;

樂觀鎖只有在 Update 時才鎖定記錄,更新完畢后停止鎖定。也就是說,每調用一次Update,都會鎖定、解鎖一次;

批量樂觀鎖表示調用UpdateBatch時鎖定記錄,批量更新完畢后停止鎖定。也就是說,每調用一次UpdateBatch,都會鎖定、解鎖一次。

假定使用悲觀鎖,多用戶執行下面三行代碼,會發生什么情況呢?

m_pRecordset->MoveFirst();

m_pRecordset->PutCollect("name","Test");

m_pRecordset->Update();

用戶A執行到m_pRecordset->PutCollect,將鎖定記錄集的第一行。其它用戶運行到m_pRecordset->PutCollect時,也想鎖定第一行,但因為已經被A鎖定,所以其它用戶執行到此行時會等待若干時間后拋出異常。

用戶A執行完m_pRecordset->Update后,將解鎖記錄集的第一行。注意:具體何時解鎖,每種數據庫好像不盡相同。經筆者測試,發現Access2000Update后即解鎖,而SQL Server2008在記錄集關閉后才解鎖。

3.2 遍歷記錄集

如下代碼將遍歷記錄集。

_variant_t var;

CString sName,sAge;

try

{

//如果 BOF EOF 均為真,則無記錄

if(!m_pRecordset->BOF || !m_pRecordset->adoEOF)

{

m_pRecordset->MoveFirst();

while(!m_pRecordset->adoEOF)

{

var = m_pRecordset->GetCollect(_T("Name"));

if(var.vt != VT_NULL)

{//姓名

sName = (LPCTSTR)_bstr_t(var);

}

else

{

sName.Empty();

}

var = m_pRecordset->GetCollect(_T("Age"));

if(var.vt != VT_NULL)

{//年齡

sAge = (LPCTSTR)_bstr_t(var);

}

else

{

sAge.Empty();

}

m_pRecordset->MoveNext();

}

}

}

catch(_com_error& e)

{

AfxMessageBox(e.Description());

}

var = m_pRecordset->GetCollect(_T("Name"));的等價代碼如下:

FieldsPtr????pFields????=????m_pRecordset->Fields;

FieldPtr????????pField????=????pFields->Item[_T("Name")];

var????????????????????=????pField->Value;

3.3 關閉記錄集

下面的代碼將關閉記錄集,并銷毀_RecordsetPtr實例。

if(m_pRecordset)

{//關閉記錄集

if(m_pRecordset->State)

{

m_pRecordset->Close();

}

//下面的語句可有可無。因為m_pRecordset是智能指針,析構時會自動Release

m_pRecordset.Release();

}

3.4 訪問BLOB

Microsoft SQL中,textimage……被當做二進制數據進行處理。

可以用Field對象的GetChunkAppendChunk方法來訪問。每次可以讀出或寫入全部數據的一部分,它會記住上次訪問的位置。但是如果中間訪問了別的字段后,就又得從頭來了。

3.4.1 寫入

可以使用m_pRecordset->PutCollect("data",varBLOB)將二進制數據一次性寫入,也可以使用AppendChunk分多次寫入二進制數據。

void CDlgMain::blobFileToDB(LPCTSTR szFile)

{

CFile f;

if(f.Open(szFile,CFile::modeRead | CFile::shareDenyWrite))

{

FieldPtr fd = m_pRecordset->Fields->Item["data"];

DWORD dwSize = f.GetLength();

if(dwSize > 0)

{

const int????????????nBlock????????= 1024;

DWORD????dwWrite????????= 0; //已經寫入數據庫的字節數

DWORD????????????dwAppend????= 0; //單次寫入的字節數

UINT????????????????uRead????????= 0;

SAFEARRAY*????psa????????= SafeArrayCreateVector(VT_UI1,0,nBlock);

_variant_t????????????vBLOB;

vBLOB.vt????????????=????VT_ARRAY | VT_UI1;

vBLOB.parray????????=????psa;

?

for(;;)

{

dwAppend = dwSize - dwWrite;

if(!dwAppend)

{

break;

}

if(dwAppend > nBlock)

{

dwAppend = nBlock;

}

SafeArrayLock(psa);

uRead = f.Read(psa->pvData,dwAppend);

SafeArrayUnlock(psa);

if(uRead != dwAppend)

{

break;

}

psa->rgsabound[0].cElements = dwAppend;

fd->AppendChunk(vBLOB);

dwWrite += dwAppend;

}

//SafeArrayDestroy(psa); //vBLOB析構時會自動釋放數組 psa

}

else

{

_variant_t vNull;

vNull.vt = VT_NULL;

fd->PutValue(vNull);

}

f.Close();

}

}

代碼fd->PutValue(vNull);相當于m_pRecordset->PutCollect("data",vNull)用來設置BLOBNULL,也就是清空。也可以使用SQL語句清空某個BLOB字段,如:

UPDATE 表名 SET BLOB字段名 = NULL WHERE ID=1

3.4.2 讀取

可以使用m_pRecordset-> GetCollect("data")將二進制數據一次性讀取出來,也可以使用GetChunk分多次讀取二進制數據。

void CDlgMain::blobDBtoFile(LPCTSTR szFile)

{

CFile f;

if(f.Open(szFile,CFile::modeWrite | CFile::modeCreate))

{

FieldPtr????fd????????????=????m_pRecordset->Fields->Item["data"];

long????????nSizeActual????=????fd->ActualSize;

if(nSizeActual > 0)

{

const int????????????nBlock????=????1024;

long????????????????nRead????=????0; ????//已經讀取的字節數

long????????????????nGet????=????0; ????//單次讀取的字節數

_variant_t????????????vBLOB;

ULONG????????????uWrite????=????0; ????//單次寫入文件的字節數

SAFEARRAY*????psa;

?

for(;;)

{

nGet = nSizeActual - nRead;

if(!nGet)

{

break;

}

if(nGet > nBlock)

{

nGet = nBlock;

}

vBLOB = fd->GetChunk(nGet);

nRead += nGet;

if(vBLOB.vt == (VT_ARRAY | VT_UI1)

&& (psa = vBLOB.parray) && psa->cDims == 1)

{

uWrite = psa->rgsabound[0].cElements;

if(uWrite)

{

SafeArrayLock(psa);

f.Write(psa->pvData,uWrite);

SafeArrayUnlock(psa);

}

}

}

}

f.Close();

}

}

3.4.3 更新

通過_CommandPtr,執行帶參數的SQL語句,可實現BLOB數據的修改。請參考_CommandPtr這一章。

3.5 書簽

書簽(bookmark)可以唯一標識記錄集中的一個記錄,用于快速地將當前記錄移回到已訪問過的記錄,以及進行過濾等等。Provider會自動為記錄集中的每一條記錄產生一個書簽,我們只需要使用它就行了。我們不能試圖顯示、修改或比較書簽。ADO用記錄集的Bookmark屬性表示當前記錄的書簽。

用法步驟:

rst->Supports(adBookmark);????????????//判斷是否支持書簽

_variant_t VarBookmark;????????????//建立書簽變量

VarBookmark = rst->Bookmark;????????//獲得書簽值

... ... ...????????????????????????//可以移動記錄

if(VarBookmark.vt != VT_EMPTY)

{//將記錄位置恢復到書簽位置

rst->Bookmark = VarBookmark;

}

3.6 過濾

Recordset對象的Filter屬性表示了當前的過濾條件。它的值可以是以ANDOR連接起來的條件表達式(不含WHERE關鍵字)、由書簽組成的數組或ADO提供的FilterGroupEnum枚舉值。為Filter屬性設置新值后Recordset的當前記錄指針會自動移動到滿足過濾條件的第一個記錄。例如:

rst->Filter = _bstr_t ("姓名='趙薇' AND 性別='女'");

在使用條件表達式時應注意下列問題:

1、可以用圓括號組成復雜的表達式

例如:

rst->Filter = _bstr_t ("(姓名='趙薇' AND 性別='女') OR AGE<25");

但是微軟不允許在括號內用OR,然后在括號外用AND,例如:

rst->Filter = _bstr_t ("(姓名='趙薇' OR 性別='女') AND AGE<25");

必須修改為:

rst->Filter = _bstr_t ("(姓名='趙薇' AND AGE<25) OR (性別='女' AND AGE<25)");

2、表達式中的比較運算符可以是LIKE

LIKE后被比較的是一個含有通配符*的字符串,星號表示若干個任意的字符。

字符串的首部和尾部可以同時帶星號*

rst->Filter = _bstr_t ("姓名 LIKE '**' ");

也可以只是尾部帶星號:

rst->Filter = _bstr_t ("姓名 LIKE '*' ");

Filter屬性值的類型是Variant,如果過濾條件是由書簽組成的數組,則需將該數組轉換為SafeArray,然后再封裝到一個VARIANT_variant_t型的變量中,再賦給Filter屬性。

3.7 Find

以下代碼用于查找記錄

pRst->Find("姓名 = '趙薇'",1,adSearchForward);

一般情況下,這種查找是順序查找,效率較低。可針對某個字段進行排序,其方法如下:

//將該字段的Optimize屬性設置為True

pRst->Fields->GetItem("姓名")->Properties->

GetItem("Optimize")->PutValue("True");

... ... ...

pRst->Find("姓名 = '趙薇'",1,adSearchForward);

... ... ...

//將該字段的Optimize屬性設置為False

pRst->Fields->GetItem("姓名")->Properties->

GetItem("Optimize")->PutValue("False");

3.8 Sort

要排序也很簡單,只要把要排序的關鍵字列表設置到Recordset對象的Sort屬性里即可,例如:

pRstAuthors->CursorLocation = adUseClient;

pRstAuthors->Open("SELECT * FROM mytable"

????????????????????,_variant_t((IDispatch *)pConnection)

????????????????????,adOpenStatic,adLockReadOnly, adCmdText);

......

pRst->Sort = "姓名 DESC, 年齡 ASC";

關鍵字(即字段名)之間用逗號隔開,如果要以某關鍵字降序排序,則應在該關鍵字后加一空格,再加DESC(如上例)。升序時ASC加不加無所謂。本操作是利用索引進行的,并未進行物理排序,所以效率較高。

但要注意,在打開記錄集之前必須將記錄集的CursorLocation屬性設置為adUseClient,如上例所示。Sort屬性值在需要時隨時可以修改。

3.9 Index

pRst->Index="";????????????//首先設置索引(數據庫里建立的索引)

pRst->Seek(...,...);????????//有序查找

3.10 綁定數據

定義一個綁定類,將其成員變量綁定到一個指定的記錄集,以方便于訪問記錄集的字段值。

3.10.1 CADORecordBinding派生類

class CCustomRs : public CADORecordBinding

{

BEGIN_ADO_BINDING(CCustomRs)

ADO_VARIABLE_LENGTH_ENTRY2(3

????????????????????????????????????????????,adVarChar

????????????????????????????????????????????,m_szau_fname

????????????????????????????????????????????,sizeof(m_szau_fname)

????????????????????????????????????????????,lau_fnameStatus

????????????????????????????????????????????,false)

ADO_VARIABLE_LENGTH_ENTRY2(2

????????????????????????????????????????????,adVarChar

????????????????????????????????????????????,m_szau_lname

????????????????????????????????????????????,sizeof(m_szau_lname)

????????????????????????????????????????????,lau_lnameStatus

????????????????????????????????????????????,false)

ADO_VARIABLE_LENGTH_ENTRY2(4

????????????????????????????????????????????,adVarChar

????????????????????????????????????????????,m_szphone

????????????????????????????????????????????,sizeof(m_szphone)

????????????????????????????????????????????,lphoneStatus

????????????????????????????????????????????,true)

END_ADO_BINDING()

public:

CHAR m_szau_fname[22];

ULONG lau_fnameStatus;

CHAR m_szau_lname[42];

ULONG lau_lnameStatus;

CHAR m_szphone[14];

ULONG lphoneStatus;

};

其中將要綁定的字段與變量名用BEGIN_ADO_BINDING宏關聯起來。每個字段對應于兩個變量,一個存放字段的值,另一個存放字段的狀態。字段用從1開始的序號表示,如123等等。

特別要注意的是:如果要綁定的字段是字符串類型,則對應的字符數組的元素個數一定要比字段長度大2(比如m_szau_fname[22],其綁定的字段au_fname的長度實際是20),不這樣綁定就會失敗。我分析多出的2可能是為了存放字符串結尾的空字符nullBSTR字符串開頭的一個字(表示BSTR的長度)。這個問題對于初學者來說可能是一個意想不到的問題。

CADORecordBinding類的定義在icrsint.h文件里,內容是:

class CADORecordBinding

{

public:

STDMETHOD_(const ADO_BINDING_ENTRY*, GetADOBindingEntries) (VOID) PURE;

};

BEGIN_ADO_BINDING宏的定義也在icrsint.h文件里,內容是:

#define BEGIN_ADO_BINDING(cls) public: /

typedef cls ADORowClass; /

const ADO_BINDING_ENTRY* STDMETHODCALLTYPE GetADOBindingEntries() { /

static const ADO_BINDING_ENTRY rgADOBindingEntries[] = {

ADO_VARIABLE_LENGTH_ENTRY2宏的定義也在icrsint.h文件里:

#define ADO_VARIABLE_LENGTH_ENTRY2(Ordinal, DataType, Buffer, Size, Status, Modify)/

{Ordinal, /

DataType, /

0, /

0, /

Size, /

offsetof(ADORowClass, Buffer), /

offsetof(ADORowClass, Status), /

0, /

classoffset(CADORecordBinding, ADORowClass), /

Modify},

#define END_ADO_BINDING宏的定義也在icrsint.h文件里:

#define END_ADO_BINDING() {0, adEmpty, 0, 0, 0, 0, 0, 0, 0, FALSE}};/

return rgADOBindingEntries;}

3.10.2 綁定

_RecordsetPtr Rs1;

IADORecordBinding *picRs=NULL;

CCustomRs rs;

......

Rs1->QueryInterface(__uuidof(IADORecordBinding),(LPVOID*) picRs);

picRs->BindToRecordset(&rs);

派生出的類必須通過IADORecordBinding接口才能綁定,調用它的BindToRecordset方法就行了。

3.10.3 讀取字段

rs中的變量即是當前記錄字段的值

//Set sort and filter condition:

// Step 4: Manipulate the data

Rs1->Fields->GetItem("au_lname")->Properties->

GetItem("Optimize")->Value = true;

Rs1->Sort = "au_lname ASC";

Rs1->Filter = "phone LIKE '415 5*'";

Rs1->MoveFirst();

while (VARIANT_FALSE == Rs1->EndOfFile)

{

printf("Name: %s/t %s/tPhone: %s/n"

,(rs.lau_fnameStatus == adFldOK ? rs.m_szau_fname : "")

,(rs.lau_lnameStatus == adFldOK ? rs.m_szau_lname : "")

,(rs.lphoneStatus == adFldOK ? rs.m_szphone : ""));

if (rs.lphoneStatus == adFldOK)

strcpy(rs.m_szphone, "777");

TESTHR(picRs->Update( // Add change to the batch

Rs1->MoveNext();

}

Rs1->Filter = (long) adFilterNone;

......

if (picRs)

{

picRs->Release();

}

Rs1->Close();

pConn->Close();

只要字段的狀態是adFldOK,就可以訪問。如果修改了字段,不要忘了先調用picRsUpdate(注意不是RecordsetUpdate),然后才關閉,也不要忘了釋放picRs(即picRs->Release();)。

3.10.4 添加新記錄

此時還可以用IADORecordBinding接口添加新記錄

if(FAILED(picRs->AddNew(&rs)))

......

?

4 _CommandPtr

_CommandPtr用來執行SQL語句或調用存儲過程。

4.1 執行SQL語句

下面的代碼首先實例化一個_CommandPtr,然后執行一條SQL語句,執行返回的結果就是一個記錄集:

_CommandPtr cmd;

cmd.CreateInstance(__uuidof(Command));

cmd->ActiveConnection????=????theApp.m_pConnection;

cmd->CommandText????????=????"select * from file where name like '%.jpg'";

_RecordsetPtr????rs????????=????cmd->Execute(NULL,NULL,adCmdText);

_CommandPtr不僅僅能執行SQL語句,它還可以給SQL語句傳遞參數。

4.1.1 無名參數

下面的代碼中,SQL語句中的?號就是一個無名參數。執行SQL語句時,從左至右第一個?號將被cmd->Parameters->Item[0]->Value代替;第二個?號將被cmd->Parameters->Item[1]->Value代替……

所以,調用cmd->Execute執行SQL語句前,需要調用cmd->CreateParameter創建參數,并調用cmd->Parameters->Append將此參數添加至cmd->Parameters集合。

_CommandPtr cmd;

cmd.CreateInstance(__uuidof(Command));

cmd->ActiveConnection????=????theApp.m_pConnection;

cmd->CommandText????????=????"select * from file where name like ?";

cmd->Parameters->Append(

????????????????cmd->CreateParameter("",adChar,adParamInput,-1,"%.jpg"));

_RecordsetPtr????rs????????=????cmd->Execute(NULL,NULL,adCmdText);

4.1.2 有名參數

下面的代碼中,SQL語句中的@name就是一個有名參數。執行SQL語句時,@name將被cmd->Parameters->Item["@name"]->Value代替。

所以,調用cmd->Execute執行SQL語句前,需要調用cmd->CreateParameter創建有名參數,并調用cmd->Parameters->Append將此參數添加至cmd->Parameters集合。

_CommandPtr cmd;

cmd.CreateInstance(__uuidof(Command));

cmd->ActiveConnection????=????theApp.m_pConnection;

cmd->CommandText????????=????"select * from file where name like @name";

cmd->Parameters->Append(

????????????????cmd->CreateParameter("@name",adChar,adParamInput,-1,"%.jpg"));

_RecordsetPtr????rs????????=????cmd->Execute(NULL,NULL,adCmdText);

4.2 修改BLOB

通過_CommandPtr,執行帶參數的SQL語句,可實現BLOB數據的修改。

_variant_t vBLOB;

vBLOB.vt = VT_ARRAY | VT_UI1;

vBLOB.parray = SafeArrayCreateVector(VT_UI1,0,30);

SafeArrayLock(vBLOB.parray);

memset(vBLOB.parray->pvData,0,30);

SafeArrayUnlock(vBLOB.parray);

?

_CommandPtr cmd(__uuidof(Command));

cmd->ActiveConnection = theApp.m_pConnection;

cmd->CommandText = "UPDATE 表名 SET BLOB字段名=? WHERE ID='1'";

cmd->Parameters->Append(

cmd->CreateParameter("",adVarBinary,adParamInput,-1,vBLOB));

cmd->Execute(NULL,NULL,adCmdText);

4.3 執行存儲過程

SQL2008里,執行如下SQL語句,創建一個存儲過程:

if exists (select * from sysobjects where id = object_id(N'[sp_1]') and OBJECTPROPERTY(id, N'IsProcedure')= 1)

drop procedure sp_1

GO

?

CREATE PROCEDURE sp_1(@pin1 int

,@pin2 CHAR(10)

,@pout1 int OUTPUT

,@pout2 CHAR(10) OUTPUT)

AS

BEGIN

declare @retval int

select @pout1 = @pin1 + 100

select @pout2 = left( ltrim(rtrim(@pin2)) + '123' , 10)

select * from [file]

select @retval = 1236

return @retval

END

GO

?

exec sp_1 10,'Test',20,'789'

GO

使用_CommandPtr執行這個存儲過程,需要傳遞、接收的參數如下:

@RETURN_VALUE(int,返回值)????????????//0個參數,返回值

@pin1(int,輸入)????????????????????????????//1個參數

@pin2(char(10),輸入)????????????????????//2個參數

@pout1(int ,輸入/輸出)????????????????????//3個參數

@pout2(char(10),輸入/輸出)????????????????//4個參數

4.3.1 無名參數

不使用Refresh方法,執行存儲過程的代碼如下:

_CommandPtr cmd;

cmd.CreateInstance(__uuidof(Command));

cmd->ActiveConnection????=????theApp.m_pConnection;

cmd->CommandText????????=????"sp_1"; //存儲過程名稱

//添加參數——返回值

cmd->Parameters->Append(

????????????cmd->CreateParameter("",adInteger,adParamReturnValue,sizeof(int)));

//添加參數——@pin1

cmd->Parameters->Append(

????????????cmd->CreateParameter("",adInteger,adParamInput,sizeof(int),3L));

//添加參數——@pin2

cmd->Parameters->Append(

????????????cmd->CreateParameter("",adChar,adParamInput,10,_variant_t(_T("DD1"))));

//添加參數——@pout1

cmd->Parameters->Append(

????????????cmd->CreateParameter("",adInteger,adParamOutput,sizeof(int)));

//添加參數——@pout2

cmd->Parameters->Append(

????????????cmd->CreateParameter("",adChar,adParamOutput,10));

//執行存儲過程

theApp.m_pConnection->CursorLocation = adUseClient;

_RecordsetPtr????rs????=????cmd->Execute(NULL,NULL,adCmdStoredProc);

//獲取執行結果

_variant_t vRet????????=????cmd->Parameters->Item[0L]->Value; //獲得返回值

_variant_t vin1????????=????cmd->Parameters->Item[1L]->Value; //獲得@pin1

_variant_t vin2????????=????cmd->Parameters->Item[2L]->Value; //獲得@pin2

_variant_t vout1????=????cmd->Parameters->Item[3L]->Value; //獲得@pout1

_variant_t vout2????=????cmd->Parameters->Item[4L]->Value; //獲得@pout2

總結:不使用Refresh方法,則調用pCmd->Parameters->Append增加參數時,必須要注意參數的順序。

4.3.2 有名參數

如果創建參數時指定參數名稱,就可以根據名稱獲取執行結果了。

//添加參數——返回值

cmd->Parameters->Append(

????cmd->CreateParameter("@RETURN_VALUE",adInteger,adParamReturnValue,sizeof(int)));

//添加參數——@pin1

cmd->Parameters->Append(

????cmd->CreateParameter("@pin1",adInteger,adParamInput,sizeof(int),3L));

//添加參數——@pin2

cmd->Parameters->Append(

????cmd->CreateParameter("@pin2",adChar,adParamInput,10,_variant_t(_T("DD1"))));

//添加參數——@pout1

cmd->Parameters->Append(

????cmd->CreateParameter("@pout1",adInteger,adParamOutput,sizeof(int)));

//添加參數——@pout2

cmd->Parameters->Append(

????cmd->CreateParameter("@pout2",adChar,adParamOutput,10));

//執行存儲過程

theApp.m_pConnection->CursorLocation = adUseClient;

_RecordsetPtr????rs????=????cmd->Execute(NULL,NULL,adCmdStoredProc);

//獲取執行結果

_variant_t vRet????????=????cmd->Parameters->Item["@RETURN_VALUE"]->Value;

_variant_t vin1????????=????cmd->Parameters->Item["@pin1"]->Value;

_variant_t vin2????????=????cmd->Parameters->Item["@pin2"]->Value;

_variant_t vout1????=????cmd->Parameters->Item["@pout1"]->Value;

_variant_t vout2????=????cmd->Parameters->Item["@pout2"]->Value;

注意:即便參數有了名稱,添加參數時的順序也不能改動。

4.3.3 Refresh

執行cmd->Parameters->Refresh();會做哪些工作呢?

1、設置cmd->Parameters->Item[0L]

設置cmd->Parameters->Item[0L]->Name "@RETURN_VALUE"

設置cmd->Parameters->Item[0L]->Value VT_EMPTY

2、設置adParamInput參數的Value VT_EMPTY

3、設置adParamOutput參數的Value VT_NULL

當第23、……次執行cmd->Execute前,可以這么做:

cmd->Parameters->Refresh();

cmd->Parameters->Item["@pin1"]->Value????=????3L;

cmd->Parameters->Item["@pin2"]->Value????=????"C";

cmd->Execute(NULL,NULL,adCmdStoredProc);????????//2次執行存儲過程

cmd->Parameters->Refresh();

cmd->Parameters->Item["@pin1"]->Value????=????4L;

cmd->Parameters->Item["@pin2"]->Value????=????"D";

cmd->Execute(NULL,NULL,adCmdStoredProc); ????????//3次執行存儲過程

4.3.4 游標位置

如果游標位置不為adUseClient,那么取returnoutput參數之前,必須把返回的記錄集關閉掉。

下面的代碼能夠正常工作。因為這行代碼執行完畢后,返回的記錄集會被銷毀,銷毀前會關閉記錄集。

pCmd->Execute(NULL,NULL,adCmdStoredProc);

下面的代碼就得注意了。在 rs 銷毀前,能否取得returnoutput參數,取決于游標位置是否為adUseClient。如果是adUseClient就能正常取值,否則必須關閉rs記錄集后,才能正常取值。

_RecordsetPtr rs = pCmd->Execute(NULL,NULL,adCmdStoredProc);

theApp.m_pConnection->CursorLocation的取值會影響到pCmd->Execute返回記錄集的游標位置。如:pCmd->Execute執行前,執行theApp.m_pConnection->CursorLocation = adUseClient,則返回記錄集的游標位置也是adUseClient

4.4 重復使用命令對象

一個命令對象如果要重復使用多次(尤其是帶參數的命令),則在第一次執行之前,應將它的Prepared屬性設置為TRUE。這樣會使第一次執行減慢,但卻可以使以后的執行全部加快。

?

?

5 ADOX

5.1 引入庫文件

#import "C:/program Files/Common Files/system/ado/msadox.dll"

5.1.1 一個BUG

打開文件msadox.tlh,可以看到以下內容。其中,enum DataTypeEnum是先使用,后聲明的。

struct __declspec(uuid("0000061d-0000-0010-8000-00aa006d2ea4"))

Columns : _Collection

{

... ... ...

HRESULT Append (

const _variant_t & Item,

enum DataTypeEnum Type,

long DefinedSize );

... ... ...

};

?

enum DataTypeEnum

{

adEmpty = 0,

adTinyInt = 16,

... ... ...

};

在此情況下,如下代碼將會出現編譯錯誤。

#import "C:/Program Files/Common Files/System/ado/msado15.dll"\

rename("EOF","adoEOF") no_namespace

#import "C:/program Files/Common Files/system/ado/msadox.dll"

原因在于:編譯msadox.tlhColumns::Append函數的第2個參數將是msado15.tlh里的enum DataTypeEnum;編譯msadox.tliColumns::Append函數的第2個參數卻變成了msadox.tlh里的JRO::DataTypeEnum

解決方法一:調整import的順序

#import "C:/program Files/Common Files/system/ado/msadox.dll"

#import "C:/Program Files/Common Files/System/ado/msado15.dll"\

rename("EOF","adoEOF") no_namespace

解決方法二:都使用命名空間

#import "C:/Program Files/Common Files/System/ado/msado15.dll"\

rename("EOF","adoEOF")

#import "C:/program Files/Common Files/system/ado/msadox.dll"

5.2 創建數據庫

ADOX::_CatalogPtr pCatalog(__uuidof(ADOX::Catalog));

_bstr_t s("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=G:\\1.mdb");

pCatalog->Create(s);

5.3 創建數據表

ADODB::_ConnectionPtr conn(__uuidof(ADODB::Connection));

conn->Open(sConn,"","",ADODB::adModeUnknown);

conn->Execute("CREATE TABLE TestTable(記錄編號 INTEGER,姓名 TEXT,年齡 INTEGER)",NULL,ADODB::adCmdText);????

conn->Close();

?

6 JRO

JROJet and Replication Objects的縮寫,它可以用來壓縮Access數據庫文件。

6.1 VB6.0

6.1.1 引用

6.1.2 代碼

Dim sSrc As String

Dim sDes As String

sSrc = "Provider=Microsoft.Jet.OLEDB.4.0;Jet OLEDB:Engine Type=5;Data Source=G:\dbFile.mdb"

sDes = "Provider=Microsoft.Jet.OLEDB.4.0;Jet OLEDB:Engine Type=5;Data Source=G:\1.mdb"

Dim oJetEngine As New JRO.JetEngine

oJetEngine.CompactDatabase sSrc, sDes

Set oJetEngine = Nothing

注意:"Jet OLEDB:Database Password="可以指定密碼。

6.2 VC++

6.2.1 引入

引入JRO需要引入ADO庫,代碼如下:

#import "C:/Program Files/Common Files/System/ado/msado15.dll"\

rename("EOF","adoEOF") no_namespace

#import "C:/Program Files (x86)/Common Files/System/ado/msjro.dll"

上面的ADO庫未使用命名空間,如果使用了命名空間,則代碼如下。增加了兩條using語句,否則無法完成編譯。

#import "C:/Program Files/Common Files/System/ado/msado15.dll"\

rename("EOF","adoEOF")

using ADODB::_Recordset;

using ADODB::_RecordsetPtr;

#import "C:/Program Files (x86)/Common Files/System/ado/msjro.dll"

6.2.2 代碼

AfxOleInit();

_bstr_t sSrc(_T("Provider=Microsoft.Jet.OLEDB.4.0;Jet OLEDB:Engine Type=5;Data Source=G:\\dbFile.mdb"));

_bstr_t sDes(_T("Provider=Microsoft.Jet.OLEDB.4.0;Jet OLEDB:Engine Type=5;Data Source=G:\\1.mdb"));

JRO::IJetEnginePtr jet(__uuidof(JRO::JetEngine));

jet->CompactDatabase(sSrc,sDes);

注意:"Jet OLEDB:Database Password="可以指定密碼。

?

?

7 常見問題

7.1 連接失敗的原因

Enterprise Managemer內,打開將服務器的屬性對話框,在Security選項卡中,有一個選項Authentication

如果該選項是Windows NT only,則你的程序所用的連接字符串就一定要包含Trusted_Connection參數,并且其值必須為yes,如:

"Provider=SQLOLEDB;Server=888;Trusted_Connection=yes"

";Database=master;uid=lad;";

如果不按上述操作,程序運行時連接必然失敗。

如果Authentication選項是SQL Server and Windows NT,則你的程序所用的連接字符串可以不包含Trusted_Connection參數,如:

"Provider=SQLOLEDB;Server=888;Database=master;uid=lad;pwd=111;";

因為ADO給該參數取的默認值就是no,所以可以省略。我認為還是取默認值比較安全一些。

7.2 改變當前數據庫

使用Tansct-SQL中的USE語句即可。

7.3 判斷某個數據庫是否存在

1、可打開master數據庫中一個叫做SCHEMATA的視圖,其內容列出了該服務器上所有的數據庫名稱。

2、更簡便的方法是使用USE語句,成功了就存在;不成功,就不存在。例如:

try

{

????m_pConnect->Execute("USE INSURANCE_2002",NULL

????????????????????????,adCmdTextadExecuteNoRecords);

}

catch(_com_error&e)

{//數據庫INSURANCE_2002不存在

}

7.4 判斷某個表是否存在

1、同樣判斷一個表是否存在,也可以用是否成功地打開它來判斷,十分方便,例如:

try

{

????m_pRecordset->Open("mytable"

????????????????????????,_variant_t((IDispatch *)m_pConnection,true)

????????????????????????,adOpenKeyset,adLockOptimistic,adCmdTable);

}

catch (_com_error &e)

{//該表不存在

}

2、要不然可以采用麻煩一點的辦法,就是在MS-SQL服務器上的每個數據庫中都有一個名為sysobjects的表,查看此表的內容即知指定的表是否在該數據庫中。

3、同樣,每個數據庫中都有一個名為TABLES的視圖(View),查看此視圖的內容即知指定的表是否在該數據庫中。

7.5 ADO鎖定整張表

Dim oConn As New ADODB.Connection

Dim oRs As New ADODB.Recordset

oConn.ConnectionTimeout = 15

oConn.Open 'Provider=SQLOLEDB.1;Password=***;Persist Security Info=True;User ID=***;Initial Catalog=XSSystem;Data Source=10.108.0.1'

oConn.CommandTimeout = 15

oConn.IsolationLevel = adXactSerializable

oConn.BeginTrans

oRs.CursorLocation = adUseClient

oRs.Open 'SELECT * FROM ShangYaoGuFenBuyTable with(tablockx) where ID='123' ', oConn, adOpenKeyset, adLockPessimistic

If oRs.RecordCount > 0 Then

MsgBox '已經有一條記錄了'

Else

oRs.AddNew

oRs('id') = '123'

oRs.Update

End If

oRs.Close

oConn.CommitTrans '在此步驟之前,ShangYaoGuFenBuyTable整張表會被鎖住,其他用戶不能進行任何訪問

oConn.Close

Set oConn = Nothing

7.6 獲取記錄集行數

可以使用SQL語句:select count(*) from 表名

7.7 解決并發沖突

使用:Field 對象的 UnderlyingValue OriginalValue 屬性;Recordset Resync 方法和 Filter 屬性。

調用UpdateBatch后,一定要立即檢查Errors集合是否有錯誤。如果有錯誤,則應檢查錯誤是否為并發沖突:

1、設置 Recordset Filter 屬性為adFilterConflictingRecords。若此時 RecordCount 屬性等于零,就說明錯誤是由沖突以外的其他原因引起的。

2、調用 Recordset Resync 方法,將 AffectRecords 參數設置為adAffectGroup,將 ResyncValues 參數設置為 adResyncUnderlyingValuesResync 方法將用來自基本數據庫中的數據刷新在當前 Recordset 對象中的數據。通過使用 adAffectGroup,可以確保只有使用當前篩選設置的情況下可見的記錄。

轉載于:https://www.cnblogs.com/hanford/p/6164335.html

總結

以上是生活随笔為你收集整理的ADO的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。