講數(shù)據(jù)庫(kù)訪問接口oledb_第1頁(yè)
講數(shù)據(jù)庫(kù)訪問接口oledb_第2頁(yè)
講數(shù)據(jù)庫(kù)訪問接口oledb_第3頁(yè)
講數(shù)據(jù)庫(kù)訪問接口oledb_第4頁(yè)
講數(shù)據(jù)庫(kù)訪問接口oledb_第5頁(yè)
已閱讀5頁(yè),還剩155頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第22講數(shù)據(jù)庫(kù)訪問接口OLEDB+ADO掌握數(shù)據(jù)世界大門的鑰匙講師:GamebabyRockSun第22講主要內(nèi)容(1)1.數(shù)據(jù)庫(kù)訪問接口簡(jiǎn)介(ODBC、OLEDB、ADO、ADO.Net)2.數(shù)據(jù)庫(kù)系統(tǒng)簡(jiǎn)介3.OLEDB簡(jiǎn)介4.MSDAC介紹和幫助獲取5.OLEDB編程基礎(chǔ)6.數(shù)據(jù)源對(duì)象和連接數(shù)據(jù)庫(kù)7.會(huì)話對(duì)象和創(chuàng)建會(huì)話事務(wù)對(duì)象8.命令對(duì)象及接口9.結(jié)果集對(duì)象及接口10.列信息獲取和動(dòng)態(tài)綁定11.數(shù)據(jù)增刪改操作及延遲提交12.多結(jié)果集對(duì)象13.SQL預(yù)處理和參數(shù)化查詢14.輸入輸出參數(shù)和存儲(chǔ)過程調(diào)用15.數(shù)據(jù)源枚舉16.無SQL直接操作表第22講主要內(nèi)容(2)17.數(shù)據(jù)源動(dòng)態(tài)結(jié)構(gòu)分析和架構(gòu)結(jié)果集18.BLOB字段插入和讀取操作19.結(jié)構(gòu)化綁定(靜態(tài)綁定)20.日期時(shí)間型數(shù)據(jù)列處理21.數(shù)據(jù)類型轉(zhuǎn)換對(duì)象22.數(shù)據(jù)變更通知23.結(jié)果集查找操作及IRowsetFind接口24.出錯(cuò)信息處理25.使用事務(wù)處理26.ATL中的OLEDB模版及用法27.ADO組件及用法28.ADO和OLEDB混合編程29.使用ADO調(diào)用存儲(chǔ)過程30.GRSLib中數(shù)據(jù)庫(kù)訪問組件的添加引言數(shù)據(jù)庫(kù)是計(jì)算機(jī)應(yīng)用系統(tǒng)中的一種專門管理數(shù)據(jù)資源的系統(tǒng).數(shù)據(jù)有多種形式:文字、數(shù)碼、符號(hào)、圖形、圖像以及聲音等.數(shù)據(jù)是所有計(jì)算機(jī)系統(tǒng)所要處理的對(duì)象.數(shù)據(jù)庫(kù)系統(tǒng)不從具體的應(yīng)用程序出發(fā),而是立足于數(shù)據(jù)本身的管理,它將所有數(shù)據(jù)保存在數(shù)據(jù)庫(kù)中,進(jìn)行科學(xué)的組織,并借助于數(shù)據(jù)庫(kù)管理系統(tǒng),以它為中介,與各種應(yīng)用程序或應(yīng)用系統(tǒng)接口,使之能方便地使用數(shù)據(jù)庫(kù)中的數(shù)據(jù).目前幾乎所有的軟件系統(tǒng)都需要與數(shù)據(jù)庫(kù)系統(tǒng)打交道(包括操作系統(tǒng)),有些系統(tǒng)更是以數(shù)據(jù)庫(kù)作為核心,因此掌握數(shù)據(jù)庫(kù)系統(tǒng)的使用方法以及數(shù)據(jù)庫(kù)系統(tǒng)編程接口的使用方法是程序員非常重要的基本技能之一.認(rèn)識(shí)數(shù)據(jù)庫(kù)系統(tǒng)數(shù)據(jù)庫(kù)系統(tǒng)是一個(gè)實(shí)際可運(yùn)行的存儲(chǔ)、維護(hù)和應(yīng)用系統(tǒng)提供數(shù)據(jù)的軟件系統(tǒng),是存儲(chǔ)介質(zhì)、處理對(duì)象和管理系統(tǒng)的集合體.它通常由軟件、數(shù)據(jù)庫(kù)和數(shù)據(jù)管理員組成.其軟件主要包括操作系統(tǒng)、各種宿主語言、實(shí)用程序以及數(shù)據(jù)庫(kù)管理系統(tǒng).數(shù)據(jù)庫(kù)由數(shù)據(jù)庫(kù)管理系統(tǒng)統(tǒng)一管理,數(shù)據(jù)的插入、修改和檢索均要通過數(shù)據(jù)庫(kù)管理系統(tǒng)進(jìn)行.數(shù)據(jù)管理員負(fù)責(zé)創(chuàng)建、監(jiān)控和維護(hù)整個(gè)數(shù)據(jù)庫(kù),使數(shù)據(jù)能被任何有權(quán)使用的人有效使用.數(shù)據(jù)庫(kù)管理員一般是由業(yè)務(wù)水平較高、資歷較深的人員擔(dān)任.數(shù)據(jù)庫(kù)系統(tǒng)的個(gè)體含義是指一個(gè)具體的數(shù)據(jù)庫(kù)管理系統(tǒng)軟件和用它建立起來的數(shù)據(jù)庫(kù);它的學(xué)科含義是指研究、開發(fā)、建立、維護(hù)和應(yīng)用數(shù)據(jù)庫(kù)系統(tǒng)所涉及的理論、方法、技術(shù)所構(gòu)成的學(xué)科.在這一含義下,數(shù)據(jù)庫(kù)系統(tǒng)是軟件研究領(lǐng)域的一個(gè)重要分支,常稱為數(shù)據(jù)庫(kù)領(lǐng)域.典型的數(shù)據(jù)庫(kù)系統(tǒng)示意圖接口1數(shù)據(jù)庫(kù)存儲(chǔ)DBMS接口2應(yīng)用1應(yīng)用2應(yīng)用3常見的DBMS系統(tǒng)Oracle:甲骨文公司出品Sybase:Sybase公司出品Informix、DB2:IBM公司出品MicrosoftSQLServer、MicrosoftAccess、VisualFoxPro:Microsoft出品MySql:瑞典MySqlAB公司出品(開源,被Sun收購(gòu)后并入Oracle公司)主要的數(shù)據(jù)庫(kù)編程組件ODBCDAORDOADOADO.NETOLEDB(本課程中將主要講解OLEDB和ADO接口的編程方法,其它接口因已不常用只做簡(jiǎn)要介紹)ODBCODBC(Open

Database

Connectivity

開放數(shù)據(jù)庫(kù)互連):是微軟公司開放服務(wù)結(jié)構(gòu)(WOSA,WindowsOpen

Services

Architecture)中有關(guān)數(shù)據(jù)庫(kù)的一個(gè)組成部分,它建立了一組規(guī)范,并提供了一組對(duì)數(shù)據(jù)庫(kù)訪問的標(biāo)準(zhǔn)API(應(yīng)用程序編程接口).這些API利用SQL來完成其大部分任務(wù).ODBC本身也提供了對(duì)SQL語言的支持,用戶可以直接將SQL語句送給ODBC.(出現(xiàn)的最早,但不總是萬能.現(xiàn)已很少使用.)DAODAO:數(shù)據(jù)訪問對(duì)象是用來顯露了Microsoft

Jet數(shù)據(jù)庫(kù)引擎(最早是給Microsoft

Access

所使用,現(xiàn)在已經(jīng)支持其它數(shù)據(jù)庫(kù)),并允許開發(fā)者通過ODBC直接連接到其他數(shù)據(jù)庫(kù)一樣,直接連接到Access表.DAO最適用于單系統(tǒng)應(yīng)用程序或在小范圍本地分布使用.其內(nèi)部已經(jīng)對(duì)Jet數(shù)據(jù)庫(kù)的訪問進(jìn)行了加速優(yōu)化,而且其使用起來也是很方便的.所以如果數(shù)據(jù)庫(kù)是Access數(shù)據(jù)庫(kù)且是本地使用的話,建議使用這種訪問方式.(應(yīng)用專一性,現(xiàn)已很少使用.)RDORDO(Remote

Data

Objects):遠(yuǎn)程數(shù)據(jù)對(duì)象是一個(gè)到ODBC的、面向?qū)ο蟮臄?shù)據(jù)訪問接口,它同易于使用的DAO

style組合在一起,提供了一個(gè)接口,形式上展示出所有ODBC的底層功能和靈活性.盡管RDO在很好地訪問Jet或ISAM數(shù)據(jù)庫(kù)方面受到限制,而且它只能通過現(xiàn)存的ODBC驅(qū)動(dòng)程序來訪問關(guān)系數(shù)據(jù)庫(kù).RDO已被證明是許多SQL

Server、Oracle以及其他大型關(guān)系數(shù)據(jù)庫(kù)開發(fā)者經(jīng)常選用的最佳接口.RDO提供了用來訪問存儲(chǔ)過程和復(fù)雜結(jié)果集的更多和更復(fù)雜的對(duì)象、屬性,以及方法.(無疑是構(gòu)建在ODBC基礎(chǔ)上的,現(xiàn)已很少使用.)ADOADO(ActiveX

Data

Object)是DAO/RDO的后繼產(chǎn)物.ADO2.0在功能上與RDO更相似,而且一般來說,在這兩種模型之間有一種相似的映射關(guān)系.ADO"擴(kuò)展"了DAO和RDO所使用的對(duì)象模型,這意味著它包含較少的對(duì)象、更多的屬性、方法(和參數(shù)),以及事件.作為最新的數(shù)據(jù)庫(kù)訪問模式,ADO的使用也是簡(jiǎn)單易用,所以微軟已經(jīng)明確表示今后把重點(diǎn)放在ADO上,對(duì)DAO/RDO不再作升級(jí),所以ADO已經(jīng)成為了當(dāng)前數(shù)據(jù)庫(kù)開發(fā)的主流.ADO涉及的數(shù)據(jù)存儲(chǔ)有DSN(數(shù)據(jù)源名稱)、ODBC(開放式數(shù)據(jù)連接)以及OLEDB三種方式.(可以說是對(duì)ODBC,OLEDB這些系統(tǒng)級(jí)的編程接口的匯接,并對(duì)DAO,RDO這些應(yīng)用級(jí)的編程接口的升級(jí),主要基于OLEDB擴(kuò)展)ADO.NETADO.NET的名稱起源于ADO(ActiveXDataObjects),這是一個(gè)廣泛的類組,用于在以往的Microsoft技術(shù)中訪問數(shù)據(jù).之所以使用ADO.NET名稱,是因?yàn)镸icrosoft希望表明,這是在.NET編程環(huán)境中優(yōu)先使用的數(shù)據(jù)訪問接口.它提供了平臺(tái)互用性和可伸縮的數(shù)據(jù)訪問.ADO.NET增強(qiáng)了對(duì)非連接編程模式的支持,并支持RICHXML由于傳送的數(shù)據(jù)都是XML格式的,因此任何能夠讀取XML格式的應(yīng)用程序都可以進(jìn)行數(shù)據(jù)處理.事實(shí)上,接受數(shù)據(jù)的組件不一定要是ADO.NET組件,它可以是基于一個(gè)MicrosoftVisualStudio的解決方案,也可以是任何運(yùn)行在其它平臺(tái)上的任何應(yīng)用程序.

ADO.NET是一組用于和數(shù)據(jù)源進(jìn)行交互的面向?qū)ο箢悗?kù).通常情況下,數(shù)據(jù)源是數(shù)據(jù)庫(kù),但它同樣也能夠是文本文件、Excel表格或者XML文件.OLEDBOLEDB是Microsoft的一個(gè)戰(zhàn)略性系統(tǒng)級(jí)編程接口,用于管理整個(gè)組織內(nèi)的數(shù)據(jù).OLEDB是建立在ODBC功能之上的一個(gè)基于COM的開放規(guī)范.ODBC是為訪問關(guān)系型數(shù)據(jù)庫(kù)而專門開發(fā)的,OLEDB則用于訪問關(guān)系型和非關(guān)系型信息源,例如主機(jī)ISAM/VSAM和層次數(shù)據(jù)庫(kù),電子郵件和文件系統(tǒng)存儲(chǔ),文本、圖形和地理數(shù)據(jù)以及自定義業(yè)務(wù)對(duì)象.(甚至可以訪問URL)

OLEDB定義了一組COM接口,對(duì)各種數(shù)據(jù)庫(kù)管理系統(tǒng)服務(wù)進(jìn)行封裝,并允許創(chuàng)建軟件組件,實(shí)現(xiàn)這些服務(wù).OLEDB組件包括數(shù)據(jù)提供程序(包含和表現(xiàn)數(shù)據(jù))、數(shù)據(jù)使用者(使用數(shù)據(jù))和服務(wù)組件(處理和傳送數(shù)據(jù),例如,查詢處理器和游標(biāo)引擎).OLEDB接口有助于平滑地集成組件,這樣,OLEDB組件廠商就可以快速地向市場(chǎng)提供高質(zhì)量OLEDB組件.此外,OLEDB包含了一個(gè)連接ODBC的“橋梁”,對(duì)現(xiàn)用的各種ODBC關(guān)系型數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序提供一貫的支持.(不是簡(jiǎn)單的取代ODBC,而是兼容ODBC)數(shù)據(jù)庫(kù)編程組件間的關(guān)系示意圖OLEDB編程基本概念在OLEDB中將接口兩端的軟件稱為數(shù)據(jù)提供者和數(shù)據(jù)消費(fèi)者(使用者).在OLEDB中,不但要考慮使用數(shù)據(jù)的一方,還要考慮提供數(shù)據(jù)的一方,比如各種數(shù)據(jù)庫(kù)系統(tǒng)幾乎都提供了自己的OLEDB接口.從本質(zhì)上說,OLEDB其實(shí)就是一個(gè)標(biāo)準(zhǔn)的數(shù)據(jù)庫(kù)與應(yīng)用系統(tǒng)間的數(shù)據(jù)標(biāo)準(zhǔn)交換接口,它的好處就是高效,通用和靈活.如果是數(shù)據(jù)提供的一方,在OLEDB中就稱之為數(shù)據(jù)提供者(簡(jiǎn)單理解為各種DBMS),如果是使用數(shù)據(jù)的一方,那么就稱之為數(shù)據(jù)消費(fèi)者(一般就是開發(fā)的使用數(shù)據(jù)庫(kù)作為支持的軟件系統(tǒng)).在本教程中將主要學(xué)習(xí)數(shù)據(jù)消費(fèi)者接口(也即數(shù)據(jù)使用端的詳細(xì)編程).MSDAC簡(jiǎn)介和幫助獲取MDAC(MicrosoftDataAccessComponents)是微軟數(shù)據(jù)庫(kù)訪問組件很多Windows中已經(jīng)存在了MDAC在MDAC中主要有三種組件:(1)ADO(2)OLEDB(3)ODBCOLEDB編程基本框架和步驟OLEDB組件對(duì)象和接口OLEDB基于COM規(guī)范打造的并擴(kuò)展了一些自有的特殊性規(guī)則;(OLEDB是基于COM的擴(kuò)展規(guī)范)其中對(duì)象接口被劃分為強(qiáng)制支持的(mandatory)和可選支持的(optional)OLEDB對(duì)象除支持OLEDB標(biāo)準(zhǔn)接口外,各個(gè)數(shù)據(jù)提供者廠商(如MSSQLServer,ORACLE等)還可提供額外的接口,用于特殊的功能支持特殊接口需要查閱相關(guān)OLEDB接口的文檔,除SQLServer的特殊接口外,其余的特殊接口在MSDN中一般沒有進(jìn)一步描述)在OLEDB中,有4個(gè)主要對(duì)象:數(shù)據(jù)源(DataSource)會(huì)話和事務(wù)(Session)命令(Command)結(jié)果集(Rowset)DataSourceObject數(shù)據(jù)源對(duì)象代表到數(shù)據(jù)庫(kù)的一個(gè)鏈接是使用或鏈接數(shù)據(jù)源需要?jiǎng)?chuàng)建的第一個(gè)對(duì)象數(shù)據(jù)源對(duì)象提供下列接口:CoTypeTDataSource{[mandatory]interfaceIDBCreateSession;[mandatory]interfaceIDBInitialize;[mandatory]interfaceIDBProperties;[mandatory]interfaceIPersist;[optional]interfaceIConnectionPointContainer;[optional]interfaceIDBAsynchStatus;[optional]interfaceIDBDataSourceAdmin;[optional]interfaceIDBInfo;[optional]interfaceIPersistFile;[optional]interfaceISupportErrorInfo;}以上任何接口被創(chuàng)建時(shí),可以認(rèn)為隱藏的DataSource對(duì)象已創(chuàng)建,并可以得到其它的接口數(shù)據(jù)源對(duì)象數(shù)據(jù)源對(duì)象一般需要完成的主要功能:進(jìn)行數(shù)據(jù)庫(kù)身份驗(yàn)證,即通過屬性給數(shù)據(jù)源提供用戶名/密碼/具體數(shù)據(jù)庫(kù)等信息以便數(shù)據(jù)源進(jìn)行身份合法性驗(yàn)證在數(shù)據(jù)提供者內(nèi)部,還要為每個(gè)鏈接準(zhǔn)備適當(dāng)?shù)木彌_,網(wǎng)絡(luò)鏈接等等資源同時(shí)數(shù)據(jù)源對(duì)象還需要設(shè)置和提供很多更高級(jí)的關(guān)于各個(gè)數(shù)據(jù)庫(kù)的詳細(xì)選項(xiàng)(比如SQLServer的鏈接超時(shí)值等)所有這些選項(xiàng)都被OLEDB規(guī)范為稱為屬性集和屬性的概念OLEDB屬性集和屬性數(shù)據(jù)使用者通過設(shè)置屬性值以請(qǐng)求特定的對(duì)象行為.例如:使用者使用屬性以指定要由行集公開的接口.數(shù)據(jù)使用者獲得屬性值,以確定對(duì)象(比如行集、會(huì)話或數(shù)據(jù)源對(duì)象)的功能.每個(gè)屬性都有值、類型、說明和讀/寫屬性,對(duì)于行集屬性,還有一個(gè)用于指示是否可以逐列應(yīng)用它的指示器.屬性由一個(gè)GUID和一個(gè)表示屬性ID的整數(shù)進(jìn)行標(biāo)識(shí).屬性集是所有具有相同GUID的一組屬性.除了預(yù)定義的OLEDB屬性集以外,一些特定DBMS的OLEDB接口如SQLServerNativeClientOLEDB訪問接口還實(shí)現(xiàn)了特定于訪問接口的屬性集和屬性集中的屬性.每個(gè)屬性屬于一個(gè)或多個(gè)屬性組.屬性組是應(yīng)用于特定對(duì)象的所有屬性所形成的組.屬性組包括初始化屬性組、數(shù)據(jù)源屬性組、會(huì)話屬性組、行集屬性組、表屬性組和列屬性組等等.在每個(gè)這樣的屬性組中都有屬性.屬性值的使用確定要設(shè)置值的屬性.確定包含所標(biāo)識(shí)屬性的屬性集.分配DBPROPSET結(jié)構(gòu)數(shù)組,每個(gè)標(biāo)識(shí)的屬性集一個(gè).為每個(gè)屬性集分配DBPROP結(jié)構(gòu)數(shù)組.每個(gè)數(shù)組中的元素個(gè)數(shù)是屬于該屬性集的屬性(在步驟1中標(biāo)識(shí))的個(gè)數(shù).填充每個(gè)屬性的DBPROP結(jié)構(gòu).在每個(gè)屬性集的DBPROPSET結(jié)構(gòu)中,填充信息(屬性集GUID、元素的計(jì)數(shù)以及對(duì)應(yīng)的DBPROP數(shù)組的指針).調(diào)用方法以設(shè)置屬性,并傳遞DBPROPSET結(jié)構(gòu)的計(jì)數(shù)和數(shù)組.為什么不用COM接口的屬性?從關(guān)于屬性和屬性集合的描述上可以看出,其實(shí)這些屬性完全可以暴露為相應(yīng)COM接口中的屬性但是為什么OLEDB中沒這樣做呢?其實(shí)主要是因?yàn)橐韵聨讉€(gè)原因:1、屬性值通常具有分組特性,用COM接口來表示需要使用多個(gè)不同的接口來包容這些屬性,為接口定義的簡(jiǎn)潔化帶來麻煩2、屬性的數(shù)量龐大,但不都是經(jīng)常使用或必須的,因此全部暴露出來為實(shí)現(xiàn)和調(diào)用帶來麻煩3、除了OLEDB標(biāo)準(zhǔn)定義的屬性外,各個(gè)具體OLEDB提供者還有各自專門的屬性集和屬性,且有些還經(jīng)常變動(dòng),這些用COM接口來暴露的話,將導(dǎo)致COM接口定義不斷變化的問題,違背COM接口一經(jīng)定義就不再變動(dòng)的原則(破壞了COM的基本規(guī)則)這給我們提供了一個(gè)現(xiàn)實(shí)的利用COM框架進(jìn)行設(shè)計(jì)時(shí)如何優(yōu)化屬性類接口設(shè)計(jì)的范例創(chuàng)建數(shù)據(jù)源對(duì)象根據(jù)COM規(guī)范,可以通過調(diào)用標(biāo)準(zhǔn)COM函數(shù)CoCreateInstance創(chuàng)建任意數(shù)據(jù)源對(duì)象的接口的方法來創(chuàng)建一個(gè)數(shù)據(jù)源對(duì)象:IDBInitialize*pIDBInitialize=NULL;CoCreateInstance(CLSID_MSDASQL,NULL,CLSCTX_INPROC_SERVER,IID_IDBInitialize,(void**)&pIDBInitialize);上面的代碼中,CLSID_MSDASQL就是真正創(chuàng)建的數(shù)據(jù)源對(duì)象的CLSID,還可以使用別的數(shù)據(jù)提供者提供的數(shù)據(jù)源對(duì)象的CLSID這也說明數(shù)據(jù)源對(duì)象的實(shí)例可以有很多種,實(shí)際中幾乎每種DBMS對(duì)應(yīng)的OLEDB接口都提供了專門的數(shù)據(jù)源對(duì)象雖然例子中只是創(chuàng)建了一個(gè)IDBInitialize的接口,但是編碼中要有實(shí)際已創(chuàng)建了一個(gè)數(shù)據(jù)源對(duì)象的認(rèn)識(shí)數(shù)據(jù)源對(duì)象的屬性數(shù)據(jù)源對(duì)象的屬性集合GUID是DBPROPSET_DBINIT其中包含下列較常用的屬性(ID):DBPROP_INIT_DATASOURCE數(shù)據(jù)源實(shí)例名DBPROP_INIT_CATALOG 目錄名(對(duì)SQLServer來說是具體的數(shù)據(jù)庫(kù)名稱,對(duì)Oracle來說無意義)DBPROP_AUTH_USERID 用戶名DBPROP_AUTH_PASSWORD 密碼連接到數(shù)據(jù)源創(chuàng)建了IDBInitialize接口之后,雖然有了數(shù)據(jù)源對(duì)象,但是并不表示已經(jīng)連接到了數(shù)據(jù)源上之后還需要設(shè)置前述的幾個(gè)基本屬性給數(shù)據(jù)源對(duì)象,以便數(shù)據(jù)提供者驗(yàn)明正身,提供鏈接并準(zhǔn)備緩沖首先需要從IDBInitialize接口Query出IDBProperties接口其次要準(zhǔn)備GUID為DBPROPSET_DBINIT的DBPROPSET結(jié)構(gòu)體和前述幾個(gè)屬性及對(duì)應(yīng)值組成的DBPROP數(shù)組調(diào)用IDBProperties接口的SetProperties方法設(shè)置上述屬性最后調(diào)用IDBInitialize的Initialize方法鏈接到數(shù)據(jù)庫(kù)斷開連接調(diào)用IDBInitialize的Uninitialize方法斷開與數(shù)據(jù)庫(kù)的連接調(diào)用IDBInitialize的Release方法釋放數(shù)據(jù)源對(duì)象IDBInitialize接口示例1-IDBInitialize項(xiàng)目演示了使用前述方法連接到數(shù)據(jù)庫(kù)的例子例子中還展示了基本的屬性和屬性集使用方法IDBInitialize接口的困境雖然前面的方法很簡(jiǎn)單便可以連接到指定的數(shù)據(jù)源上,但是這種簡(jiǎn)單的方法有些無法克服的問題首先就是這種創(chuàng)建方法本質(zhì)上是依托于標(biāo)準(zhǔn)COM接口的創(chuàng)建方法,因此無法在標(biāo)準(zhǔn)COM創(chuàng)建的基礎(chǔ)上做很多擴(kuò)展初始化的工作這導(dǎo)致這種方法雖然創(chuàng)建了數(shù)據(jù)源對(duì)象,但是對(duì)象特有的一些功能無法使用(比如后期需要IRowsetFind等高級(jí)接口功能時(shí)可能無法獲得IRowsetFind接口)為此OLEDB2.0之后又特別提供了兩個(gè)接口IDataInitialize和IDBPromptInitialize作為數(shù)據(jù)源創(chuàng)建對(duì)象來創(chuàng)建數(shù)據(jù)源對(duì)象這樣就繞開了直接使用標(biāo)準(zhǔn)COM方法創(chuàng)建數(shù)據(jù)源對(duì)象帶來的問題IDBPromptInitialize接口IDBPromptInitialize為創(chuàng)建OLEDB數(shù)據(jù)源對(duì)象提供了一個(gè)可視化的對(duì)話框通過這個(gè)對(duì)話框,用戶可以快速選定OLEDB具體的提供者以及快速設(shè)置包括數(shù)據(jù)源/用戶/密碼等屬性以及其它擴(kuò)展屬性通過調(diào)用該接口的PromptDataSource方法即可彈出OLEDB數(shù)據(jù)源對(duì)話框并且最終返回IDBInitialize接口IDataInitialize接口IDataInitialize接口除了可以用來替代CoCreateInstance來創(chuàng)建數(shù)據(jù)源對(duì)象之外還提供了豐富的功能使用IDataInitialize接口可以通過一個(gè)連接字符串的方式連接到指定的數(shù)據(jù)源通過從IDBPromptInitialize接口Query出IDataInitialize接口可以直接得到一個(gè)連接字符串使用數(shù)據(jù)源對(duì)象創(chuàng)建對(duì)象示例A-DataSource項(xiàng)目演示了使用前述兩個(gè)接口來創(chuàng)建數(shù)據(jù)源對(duì)象的示例在實(shí)際的OLEDB代碼中,都推薦使用該示例中的方法來創(chuàng)建數(shù)據(jù)源對(duì)象和連接Session事務(wù)對(duì)象事務(wù)是一種對(duì)數(shù)據(jù)源的一系列更新進(jìn)行分組或批處理以便當(dāng)所有更新都成功時(shí)同時(shí)提交這些更新,或者如果任何一個(gè)更新失敗則不提交任何更新并且回滾整個(gè)事務(wù)的方法.事務(wù)確保了數(shù)據(jù)源上數(shù)據(jù)的完整性.OLEDB通過下列三種方法支持事務(wù):ITransactionLocal::StartTransactionITransaction::CommitITransaction::Abort會(huì)話和事務(wù)對(duì)象接口OLEDB中會(huì)話和事務(wù)對(duì)象標(biāo)準(zhǔn)接口定義如下:CoTypeTSession{[mandatory]interfaceIGetDataSource;[mandatory]interfaceIOpenRowset;[mandatory]interfaceISessionProperties;[optional]interfaceIAlterIndex;[optional]interfaceIAlterTable;[optional]interfaceIBindResource;[optional]interfaceICreateRow;[optional]interfaceIDBCreateCommand;[optional]interfaceIDBSchemaRowset;[optional]interfaceIIndexDefinition;[optional]interfaceISupportErrorInfo;[optional]interfaceITableCreation;[optional]interfaceITableDefinition;[optional]interfaceITableDefinitionWithConstraints;[optional]interfaceITransaction;[optional]interfaceITransactionJoin;[optional]interfaceITransactionLocal;[optional]interfaceITransactionObject;}會(huì)話和事務(wù)單個(gè)數(shù)據(jù)源對(duì)象可以創(chuàng)建一個(gè)或多個(gè)會(huì)話對(duì)象,每個(gè)會(huì)話對(duì)象都可以在給定時(shí)間位于事務(wù)范圍內(nèi)或范圍外.如果會(huì)話未進(jìn)入事務(wù),則在該會(huì)話中對(duì)數(shù)據(jù)存儲(chǔ)區(qū)所做的所有工作都會(huì)在每個(gè)方法調(diào)用后立即提交.(這有時(shí)稱為自動(dòng)提交模式或隱式模式.)如果會(huì)話進(jìn)入事務(wù),則在該會(huì)話中對(duì)數(shù)據(jù)存儲(chǔ)區(qū)所做的所有工作都成為該事務(wù)的組成部分并作為單個(gè)單元提交或中止.(這有時(shí)稱為手動(dòng)提交模式.)事務(wù)支持是特定于提供程序的.如果所使用的提供程序支持事務(wù),則支持ITransaction和ITransactionLocal的會(huì)話對(duì)象便可以進(jìn)入簡(jiǎn)單(即非嵌套)的事務(wù).啟動(dòng)和結(jié)束事務(wù)在使用者的行集合對(duì)象中調(diào)用StartTransaction、Commit和Abort方法.調(diào)用ITransactionLocal::StartTransaction將啟動(dòng)一個(gè)新的本地事務(wù).啟動(dòng)事務(wù)后,由隨后的操作強(qiáng)制進(jìn)行的任何更改只有在提交該事務(wù)時(shí)才會(huì)實(shí)際應(yīng)用于數(shù)據(jù)存儲(chǔ)區(qū).調(diào)用ITransaction::Commit或ITransaction::Abort將結(jié)束該事務(wù).Commit使該事務(wù)范圍內(nèi)的所有更改都應(yīng)用于數(shù)據(jù)存儲(chǔ)區(qū).Abort使該事務(wù)范圍內(nèi)的所有更改都被取消,并且數(shù)據(jù)存儲(chǔ)區(qū)將保持在啟動(dòng)該事務(wù)之前的狀態(tài).嵌套事務(wù)如果在會(huì)話中已經(jīng)存在一個(gè)活動(dòng)事務(wù)時(shí)啟動(dòng)一個(gè)新的本地事務(wù),則發(fā)生嵌套事務(wù).新的事務(wù)將作為當(dāng)前事務(wù)下的嵌套事務(wù)啟動(dòng).如果提供程序不支持嵌套事務(wù),則在會(huì)話中已經(jīng)存在一個(gè)活動(dòng)事務(wù)時(shí)調(diào)用StartTransaction將返回XACT_E_XTIONEXISTS.分布式事務(wù)分布式事務(wù)是用于更新分布式數(shù)據(jù)(即位于一個(gè)以上網(wǎng)絡(luò)計(jì)算機(jī)系統(tǒng)上的數(shù)據(jù))的事務(wù).支持分布式事務(wù)的提供者支持ITransactionJoin接口會(huì)話事務(wù)對(duì)象特殊擴(kuò)展接口IDBSchemaRowset:數(shù)據(jù)庫(kù)結(jié)構(gòu)解析IIndexDefinition:索引定義ITableCreation:表創(chuàng)建ITableDefinition:表定義ITableDefinitionWithConstraints:帶約束的表定義IAlterIndex:索引變更IAlterTable:表變更事務(wù)屬性和事務(wù)隔離級(jí)別在SQL-92中定義了事務(wù)的隔離級(jí)別,在OLEDB中可以通過ISessionProperties接口以屬性的方式來設(shè)置事務(wù)的隔離級(jí)別在OLEDB中Session對(duì)象僅有一個(gè)屬性集合DBPROPSET_SESSION,該集合中也只有一個(gè)屬性DBPROP_SESS_AUTOCOMMITISOLEVELS用來設(shè)置當(dāng)前會(huì)話的事務(wù)隔離級(jí)別另外可以通過調(diào)用ITransactionLocal::StartTransaction時(shí)指定isoLevel參數(shù)的方式來設(shè)定新建事務(wù)的隔離級(jí)別(關(guān)于事務(wù)隔離級(jí)別的概念可以查閱相關(guān)的標(biāo)準(zhǔn)文檔,維基百科中有標(biāo)準(zhǔn)規(guī)范的描述)會(huì)話事務(wù)對(duì)象的創(chuàng)建在擁有了數(shù)據(jù)源對(duì)象之后,通過已有接口Query出IDBCreateSession接口然后調(diào)用IDBCreateSession::CreateSession方法創(chuàng)建一個(gè)Session對(duì)象的接口,也即創(chuàng)建一個(gè)新的Session對(duì)象需要注意的是一個(gè)數(shù)據(jù)源對(duì)象可以用來創(chuàng)建多個(gè)Session對(duì)象及接口,創(chuàng)建多少個(gè)一般沒有限制這里要注意的是不能用CoCreateInstance標(biāo)準(zhǔn)方法來創(chuàng)建Session對(duì)象及接口這種創(chuàng)建新的對(duì)象及接口的方式也是對(duì)COM規(guī)范本身的擴(kuò)展,是一種基于COM設(shè)計(jì)系統(tǒng)時(shí)的擴(kuò)展設(shè)計(jì)模式默認(rèn)的Session對(duì)象的事務(wù)隔離級(jí)別是自動(dòng)提交級(jí)別(為進(jìn)一步確定可調(diào)用ISessionProperties::GetProperties來檢查)為了能夠正常進(jìn)行后續(xù)的處理任務(wù),一般應(yīng)用中至少應(yīng)創(chuàng)建一個(gè)Session對(duì)象(很多簡(jiǎn)單應(yīng)用中創(chuàng)建一個(gè)也就夠用了)Session對(duì)象創(chuàng)建示例B-SessionObject項(xiàng)目演示了如何創(chuàng)建一個(gè)會(huì)話事務(wù)對(duì)象在例子中特意演示了通過查詢接口的方式判斷數(shù)據(jù)提供者都支持那些功能Command對(duì)象對(duì)于像數(shù)據(jù)庫(kù)這類數(shù)據(jù)源,操作的最好方法就是使用SQL語句在OLEDB中對(duì)執(zhí)行SQL語句提供了完整的支持,實(shí)現(xiàn)這一功能最重要的對(duì)象就是Command以下是Command原型定義:CoTypeTCommand{[mandatory]interfaceIAccessor;[mandatory]interfaceIColumnsInfo;[mandatory]interfaceICommand;[mandatory]interfaceICommandProperties;[mandatory]interfaceICommandText;[mandatory]interfaceIConvertType;[optional]interfaceIColumnsRowset;[optional]interfaceICommandPersist;[optional]interfaceICommandPrepare;[optional]interfaceICommandWithParameters;[optional]interfaceISupportErrorInfo;[optional]interfaceICommandStream;}Command對(duì)象狀態(tài)根據(jù)SQL語句被設(shè)置和處理的過程,一個(gè)Command對(duì)象可以有以下4個(gè)狀態(tài):Initial:初始狀態(tài)Unprepared:未預(yù)處理狀態(tài)(已設(shè)置SQL,但沒有預(yù)處理)Prepared:已預(yù)處理狀態(tài)Executed:已執(zhí)行狀態(tài)以上4個(gè)狀態(tài)可以相互轉(zhuǎn)化,已預(yù)處理狀態(tài)有時(shí)可以被跳過可以直接執(zhí)行的SQL語句可以通過Command對(duì)象直接執(zhí)行,而無需預(yù)處理Command對(duì)象的創(chuàng)建再擁有了Session對(duì)象之后就可以創(chuàng)建Command對(duì)象了一般通過Query出Session對(duì)象的IDBCreateCommand接口后,就可以創(chuàng)建Command對(duì)象了需要注意的是IDBCreateCommand接口是個(gè)可選接口,這是因?yàn)椴⒉皇撬械腛LEDB提供者都支持命令處理(比如SQL語句處理),所以該接口為可選項(xiàng)在使用Command對(duì)象時(shí),一定要先確定能夠從Session對(duì)象得到IDBCreateCommand接口即使一個(gè)數(shù)據(jù)提供者不支持Command對(duì)象,依然可以通過直接打開數(shù)據(jù)對(duì)象的方法來操作其數(shù)據(jù),這在后面講結(jié)果集對(duì)象時(shí)介紹最后需要記住的是一個(gè)Session對(duì)象可以創(chuàng)建多個(gè)Command對(duì)象Command對(duì)象創(chuàng)建示例C-CommandObject項(xiàng)目演示了通過Session對(duì)象創(chuàng)建Command對(duì)象的例子例子中還通過查詢所有Command對(duì)象接口的方式來確定數(shù)據(jù)提供者支持的Command對(duì)象的功能執(zhí)行SQL命令創(chuàng)建Command對(duì)象的真實(shí)目的就是為了處理和執(zhí)行一個(gè)SQL命令從另一個(gè)角度說如果能夠方便的執(zhí)行SQL語句了,那么意味著實(shí)際已可以對(duì)數(shù)據(jù)源進(jìn)行任何方式的處理但是既然有了OLEDB接口,也可以執(zhí)行SQL語句,依然鼓勵(lì)某些功能還是使用OLEDB接口來進(jìn)行這是因?yàn)镾QL語句的執(zhí)行需要經(jīng)過解析緩沖執(zhí)行等過程,有些SQL語句還可能因?yàn)榫帉憜栴}導(dǎo)致效率低下,所以對(duì)于一些任務(wù)鼓勵(lì)使用OLEDB接口這種直接的編程方式來替代SQL語句的執(zhí)行,比如:數(shù)據(jù)更改,新增,刪除等等通常執(zhí)行一些SQL命令后會(huì)返回一個(gè)結(jié)果集對(duì)象,而有些SQL語句并不返回結(jié)果集對(duì)象執(zhí)行SQL命令利用Command對(duì)象執(zhí)行SQL語句時(shí),需要先得到ICommandText接口調(diào)用ICommandText::SetCommandText設(shè)置SQL命令接著調(diào)用ICommand::Execute方法執(zhí)行該命令,并得到可能的結(jié)果集對(duì)象的接口指針(通常是IRowset*)這里要注意的是,OLEDB并沒有規(guī)定被執(zhí)行的命令必須是SQL語句,這個(gè)是數(shù)據(jù)提供者的要求,因?yàn)橐话闶褂玫氖菙?shù)據(jù)庫(kù)這類數(shù)據(jù)源,所以經(jīng)常使用的就是SQL語言命令因此掌握SQL語言也是對(duì)程序員的一個(gè)基本要求執(zhí)行SQL示例D-ExecuteSQL項(xiàng)目演示了如何利用Command對(duì)象執(zhí)行一條SQL命令的方法和過程例子還演示了如何設(shè)置Command對(duì)象的屬性執(zhí)行SQL語句而忽略結(jié)果有些情況下應(yīng)用程序在執(zhí)行SQL語句時(shí)往往不需要返回的結(jié)果集,或者只是執(zhí)行一些本身并不返回任何結(jié)果集的SQL語句,此時(shí)可以像下面這樣調(diào)用即可:pICommandText->Execute(NULL,IID_NULL,NULL,NULL,NULL);Command對(duì)象的屬性與之前的DataSource對(duì)象和Session對(duì)象不同,Command對(duì)象的屬性最終并不影響Command對(duì)象自身而是作用于由執(zhí)行命令而產(chǎn)生的結(jié)果集對(duì)象這些屬性通常必須在SQL命令執(zhí)行并得到結(jié)果集之前通過ICommandProperties::SetProperties設(shè)置這些屬性的屬性集ID是DBPROPSET_ROWSET,該屬性集中有很多能夠最終影響Rowset對(duì)象的屬性這些屬性的最終行為就充分展示了OLEDB編程接口的靈活性后面的討論中講逐步介紹其中一些重要的屬性和用法結(jié)果集對(duì)象Rowset結(jié)果集對(duì)象一般是執(zhí)行SQL語句以后返回的一個(gè)代表二維結(jié)構(gòu)化數(shù)組的對(duì)象,其原型為:CoTypeTRowset{[mandatory]interfaceIAccessor;[mandatory]interfaceIColumnsInfo;[mandatory]interfaceIConvertType;[mandatory]interfaceIRowset;[mandatory]interfaceIRowsetInfo;[optional]interfaceIChapteredRowset;[optional]interfaceIColumnsInfo2;[optional]interfaceIColumnsRowset;[optional]interfaceIConnectionPointContainer;[optional]interfaceIDBAsynchStatus;[optional]interfaceIGetRow;[optional]interfaceIRowsetChange;[optional]interfaceIRowsetChapterMember;[optional]interfaceIRowsetCurrentIndex;[optional]interfaceIRowsetFind;[optional]interfaceIRowsetIdentity;[optional]interfaceIRowsetIndex;[optional]interfaceIRowsetLocate;[optional]interfaceIRowsetRefresh;[optional]interfaceIRowsetScroll;[optional]interfaceIRowsetUpdate;[optional]interfaceIRowsetView;[optional]interfaceISupportErrorInfo;[optional]interfaceIRowsetBookmark;}結(jié)果集對(duì)象的一般用法一般通過得到IRowset接口指針來得到結(jié)果集對(duì)象首先Query出IColumnsInfo接口通過調(diào)用IColumnsInfo::GetColumnInfo方法得到關(guān)于結(jié)果集的列的詳細(xì)信息DBCOLUMNINFO結(jié)構(gòu)的數(shù)組,包括:列序號(hào),列名,類型,字節(jié)長(zhǎng)度,精度,比例等通過該結(jié)構(gòu)數(shù)組,準(zhǔn)備一個(gè)對(duì)應(yīng)的DBBINDING結(jié)構(gòu)數(shù)組,并計(jì)算每行數(shù)據(jù)實(shí)際需要的緩沖大小利用DBBINDING數(shù)組和IAccessor::CreateAccessor方法創(chuàng)建一個(gè)數(shù)據(jù)訪問器并得到句柄HACCESSOR調(diào)用IRowset::GetNextRow遍歷行指針到下一行,第一次調(diào)用就是指向第一行,并得到行句柄HROW調(diào)用IRowset::GetData傳入準(zhǔn)備好的行緩沖內(nèi)存指針,以及之前創(chuàng)建的訪問器HACCESSOR句柄和HROW句柄最終行數(shù)據(jù)就被放置到了指定的緩沖中循環(huán)調(diào)用GetNextRow和GetData即可遍歷整個(gè)二維結(jié)果集結(jié)果集對(duì)象示例E-RowsetObject項(xiàng)目演示了如何從Command對(duì)象得到一個(gè)Rowset對(duì)象,并通過QueryRowset對(duì)象的所有接口的方式來了解具體的屬性對(duì)Rowset對(duì)象接口的影響F-Binding項(xiàng)目演示了如何通過簡(jiǎn)單的綁定得到并遍歷整個(gè)結(jié)果集并顯示出最終的數(shù)據(jù)列信息的獲取取得結(jié)果集對(duì)象后,緊接著的操作一般就是獲取結(jié)果集的結(jié)構(gòu)信息,也就是獲取結(jié)果集的列信息(有些材料中稱為字段信息)要獲取列信息,就需要QueryInterface出結(jié)果集對(duì)象的IColumnsInfo接口,并調(diào)用IColumnsInfo::GetColumnInfo方法獲得一個(gè)稱為DBCOLUMNINFO結(jié)構(gòu)體的數(shù)組該結(jié)構(gòu)體中反映了列的邏輯結(jié)構(gòu)信息(抽象數(shù)據(jù)類型)和物理結(jié)構(gòu)信息(內(nèi)存需求大小等信息)DBCOLUMNINFOtypedefstructtagDBCOLUMNINFO{LPOLESTR

pwszName;ITypeInfo*

pTypeInfo;DBORDINAL

iOrdinal;DBCOLUMNFLAGS

dwFlags;DBLENGTH

ulColumnSize;DBTYPE

wType;BYTE

bPrecision;BYTE

bScale;DBID

columnid;}DBCOLUMNINFO;其中pwszName字段中存放的是列名稱,一般是一個(gè)UNICODE字符串pTypeInfo目前還未使用iOrdinal是列序號(hào),一般從1開始,當(dāng)該序號(hào)為0時(shí)是用于指定特殊列(后面會(huì)有專門討論)dwFlags是一個(gè)按位設(shè)置的關(guān)于該列的標(biāo)志信息(其位值在DBCOLUMNFLAGS枚舉中定義)ulColumnSize是該列的最大字節(jié)大小(根據(jù)具體列數(shù)據(jù)類型的不同其具體含義有差異)wType表示該列的類型(其值由DBTYPEENUM枚舉值定義)bPrecision指出該列的精度(數(shù)值型有意義)bScale指出該列的比例columnid指出了該列信息在數(shù)據(jù)庫(kù)字典表中存儲(chǔ)的ID從列信息到綁定信息有了二維結(jié)果集的列信息之后,就可以著手讀取二維結(jié)果集數(shù)據(jù)的工作了但是在OLEDB中有了列信息并不表示可以直接開始讀取行數(shù)據(jù)了這中間還需要執(zhí)行一步稱為綁定的操作綁定通常需要執(zhí)行兩個(gè)步驟:1、根據(jù)前面的列信息建立綁定結(jié)構(gòu)數(shù)組(DBBINDING);2、使用綁定結(jié)構(gòu)數(shù)組創(chuàng)建訪問器(HACCESSOR);之所以這樣做的原因是:1、不是所有的數(shù)據(jù)類型都是能夠被使用程序直接支持的;2、有時(shí)一行數(shù)據(jù)不能完全讀取到內(nèi)存中;3、不是所有的訪問器都是為了讀取數(shù)據(jù);4、使用綁定可以靈活的安排行數(shù)據(jù)在內(nèi)存中的排放方式;綁定過程是OLEDB接口較之其它接口最具特色和最靈活的地方數(shù)據(jù)綁定詳解(1)對(duì)綁定最簡(jiǎn)單的理解:數(shù)據(jù)使用者安排得到數(shù)據(jù)的內(nèi)存擺放方式,并將這一方式告訴數(shù)據(jù)提供者,讓其按要求將數(shù)據(jù)擺放到指定的內(nèi)存緩存中為了這個(gè)目的,就需要?jiǎng)?chuàng)建一個(gè)被稱作DBBINDING的結(jié)構(gòu)數(shù)組,下面是該結(jié)構(gòu)體的原型:typedefstructtagDBBINDING{DBORDINAL

iOrdinal;DBBYTEOFFSET

obValue;DBBYTEOFFSET

obLength;DBBYTEOFFSET

obStatus;ITypeInfo*

pTypeInfo;DBOBJECT*

pObject;DBBINDEXT*

pBindExt;DBPART

dwPart;DBMEMOWNER

dwMemOwner;DBPARAMIO

eParamIO;DBLENGTH

cbMaxLen;DWORD

dwFlags;DBTYPE

wType;BYTE

bPrecision;BYTE

bScale;}DBBINDING;數(shù)據(jù)綁定詳解(2)這個(gè)結(jié)構(gòu)與DBCOLUMNINFO結(jié)構(gòu)很相似,實(shí)際它的字段大多可以直接使用DBCOLUMNINFO對(duì)應(yīng)字段進(jìn)行賦值但是二者字段的用途確是完全不同的:1、DBCOLUMNINFO是數(shù)據(jù)提供者給使用者的信息,它是固定的,對(duì)相同的查詢來說,列總是相同的,因此數(shù)據(jù)提供者返回的DBCOLUMNINFO數(shù)組也是固定的.2、DBBINDING是作為數(shù)據(jù)消費(fèi)者創(chuàng)建之后給數(shù)據(jù)提供者的一個(gè)結(jié)構(gòu)數(shù)組,它的內(nèi)容則由調(diào)用者來完全控制,通過這個(gè)結(jié)構(gòu)可以指定數(shù)據(jù)提供者最終將數(shù)據(jù)擺放成調(diào)用者指定的格式,并進(jìn)行指定的數(shù)據(jù)類型轉(zhuǎn)換.3、DBCOLUMNINFO反映的是二維結(jié)果集的原始列結(jié)構(gòu)信息4、DBBINDING則反映的是二維結(jié)果集數(shù)據(jù)最終按要求擺放在內(nèi)存中的樣式DBBINDING和數(shù)據(jù)內(nèi)存擺放DBBINGING[0].obStatusDBBINGING[0].obLengthDBBINGING[0].obValueStatus1Length1Value1Status2Length2Value2StatusNLengthNValue(N)......DBBINGING[1].obStatusDBBINGING[1].obLengthDBBINGING[1].obValueDBBINGING[n-1].obStatusDBBINGING[n-1].obLengthDBBINGING[n-1].obValueOneRowLengthOffset4*nBytesAligned4*nBytesAligned重看BINDING例子再深入理解了綁定的原理和作用之后重新查看F-Binding項(xiàng)目代碼,最終搞懂BINDING原理和用法執(zhí)行SQL與使用OLEDB編程接口比較數(shù)據(jù)存儲(chǔ)SQL語句SQL編譯器OLEDB組件數(shù)據(jù)庫(kù)核心引擎(可執(zhí)行組件)執(zhí)行計(jì)劃(緩存)應(yīng)用程序執(zhí)行SQL與使用OLEDB編程接口比較從前圖可以看出執(zhí)行SQL語句來操作數(shù)據(jù)庫(kù)數(shù)據(jù)的方式必須要經(jīng)歷一個(gè)耗時(shí)的SQL編譯階段在大規(guī)模應(yīng)用中,使用SQL語句來進(jìn)行數(shù)據(jù)庫(kù)的操作將付出高昂的代價(jià)(如果再考慮多客戶端并發(fā)操作時(shí)優(yōu)化所有SQL的代價(jià)更高昂)比如向數(shù)據(jù)庫(kù)使用Insert語句插入成千上萬條記錄時(shí),效率問題表現(xiàn)更突出而使用OLEDB對(duì)應(yīng)功能接口使用編程的方式,則明顯直接和高效的多(相當(dāng)于直接操作數(shù)據(jù)庫(kù)引擎)對(duì)于數(shù)據(jù)的增刪改操作建議使用OLEDB相應(yīng)編程接口進(jìn)行對(duì)于數(shù)據(jù)的復(fù)雜動(dòng)態(tài)查詢不做此要求數(shù)據(jù)的變更操作通常可以執(zhí)行SQL語句后,對(duì)數(shù)據(jù)的增刪改操作就可以利用SQL語句的方式來進(jìn)行但是執(zhí)行SQL的效率和性能在大規(guī)模應(yīng)用中很不近人意此時(shí)可以使用OLEDB中Rowset對(duì)象的專用更新接口進(jìn)行編程的方式進(jìn)行數(shù)據(jù)增刪改操作數(shù)據(jù)修改的主要功能接口是IRowsetChangeIRowsetChange::DeleteRows刪除行IRowsetChange::InsertRow 插入新行IRowsetChange::SetData 修改行中列數(shù)據(jù)通過該接口可以直接對(duì)數(shù)據(jù)進(jìn)行無SQL式的增刪改操作打開IRowsetChange接口在默認(rèn)情況下打開的Rowset對(duì)象是不支持增刪改操作的,這主要是因?yàn)閿?shù)據(jù)源為了效能等方面的考慮要對(duì)結(jié)果集進(jìn)行變更操作時(shí)必須通過設(shè)置屬性的方式顯式的打開IRowsetChange接口需要設(shè)置的屬性ID是DBPROP_UPDATABILITY,屬于DBPROPSET_ROWSET屬性集該屬性有3個(gè)可按位或設(shè)置的候選值:DBPROPVAL_UP_CHANGE:打開SetDataDBPROPVAL_UP_DELETE:打開DeleteRowsDBPROPVAL_UP_INSERT:打開InsertRow之所以將增刪改功能屬性分開,也是為了給數(shù)據(jù)提供者有機(jī)會(huì)進(jìn)行精細(xì)化的性能優(yōu)化考慮打開IRowsetChange接口的特殊要求如果需要對(duì)結(jié)果集進(jìn)行增刪改操作,那么除了通過設(shè)置屬性打開IRowsetChange接口外還需要注意一個(gè)特殊的地方,即必須使用IRowsetChange替代IRowset等接口,作為創(chuàng)建并打開結(jié)果集對(duì)象的第一個(gè)接口比如在使用ICommand::Execute函數(shù)時(shí)就需要像下面這樣調(diào)用:pICommand->Execute(NULL,IID_IRowsetChange,NULL

,NULL,(IUnknown**)&pIRowsetChange);這個(gè)要求與一般的OLEDB對(duì)象接口創(chuàng)建原則有差異數(shù)據(jù)修改的模式一般調(diào)用IRowsetChange接口的增刪改方法對(duì)數(shù)據(jù)做出的修改都會(huì)立即反映到數(shù)據(jù)源數(shù)據(jù)庫(kù)中(稱為立即模式)對(duì)于一般的應(yīng)用來說這雖然繞開了全部使用SQL語句的低效模式,但是有以下問題:1-修改立刻反映到數(shù)據(jù)源中,不利于數(shù)據(jù)完整性維護(hù)和數(shù)據(jù)安全性;2-如果是網(wǎng)絡(luò)數(shù)據(jù)庫(kù)模式,這會(huì)形成很多小規(guī)模的網(wǎng)絡(luò)包傳輸,造成網(wǎng)絡(luò)利用效率低下;因此OLEDB中還提供了另一種模式——延遲更新模式延遲更新模式延遲更新模式本質(zhì)上提供了一種對(duì)所有修改進(jìn)行緩沖并最終一次性提交的機(jī)制(注意不要理解為事務(wù)方式)該模式有如下優(yōu)點(diǎn):1-當(dāng)多個(gè)客戶端都在修改同一數(shù)據(jù)源數(shù)據(jù)時(shí),可以有機(jī)會(huì)對(duì)已作出的修改通知給別的客戶端2-可以合并對(duì)一行數(shù)據(jù)中的多列數(shù)據(jù)的修改并一次性提交到數(shù)據(jù)源中3-網(wǎng)絡(luò)模式下,可以將多個(gè)修改同一數(shù)據(jù)表(或別的對(duì)象)的多個(gè)操作形成的包合并成一個(gè)大包傳輸,提高網(wǎng)絡(luò)傳輸效率4-當(dāng)更改不合適時(shí),可以調(diào)用IRowsetUpdate::Undo選擇放棄修改打開延遲更新接口要使用延遲更新特性,必須申請(qǐng)打開結(jié)果集對(duì)象的IRowsetUpdate接口與IRowsetChange接口類似該接口也需要通過設(shè)置特殊屬性DBPROP_IRowsetUpdate來打開,該屬性也屬于DBPROPSET_ROWSET屬性集如果需要同時(shí)緩沖修改/刪除和新增的新行時(shí),還需要額外打開DBPROP_CANHOLDROWS屬性這兩個(gè)屬性都是VARIANT_BOOL型變量,屬性值設(shè)置為VARIANT_TRUE即表示要求打開這兩個(gè)屬性要打開延遲更新接口,必須先打開IRowsetChange接口使用OLEDB更新數(shù)據(jù)時(shí)的細(xì)節(jié)問題如果打開了DBPROP_CANHOLDROWS屬性,為了方便管理,一般數(shù)據(jù)提供者都會(huì)為返回的結(jié)果集額外生成一個(gè)第0列,作為數(shù)據(jù)消費(fèi)者和數(shù)據(jù)提供者直接對(duì)照行號(hào)的憑據(jù)通常該列為INT型值,并且由數(shù)據(jù)提供者來維護(hù),數(shù)據(jù)消費(fèi)者要對(duì)數(shù)據(jù)進(jìn)行增刪改操作時(shí)一般不能對(duì)該列進(jìn)行修改操作(即該列對(duì)于數(shù)據(jù)消費(fèi)者來說是只讀列)但此列可以作為一個(gè)行序號(hào)讀取并顯示出來,此時(shí)需要考慮的問題是創(chuàng)建至少兩個(gè)行訪問器,一個(gè)綁定第0列作為讀取使用,另一個(gè)不綁定第0列,作為變更數(shù)據(jù)專用訪問器一般情況下可以通過檢測(cè)返回結(jié)果集中的列信息中的標(biāo)志字段來確定哪些列可以進(jìn)行變更,哪些列是只讀列等標(biāo)志來創(chuàng)建多個(gè)不同用途的行訪問器延遲更新行狀態(tài)遷移數(shù)據(jù)更新示例G-DelayUpdate項(xiàng)目演示了如何使用結(jié)果集對(duì)象的變更接口來進(jìn)行變更操作的例子,并且使用了延遲更新特性使用延遲更新模式,可以開發(fā)出類似PowerBuild中的數(shù)據(jù)窗口式的控件來提高開發(fā)效率多結(jié)果集接口IMultipleResults有些任務(wù)中,需要傳遞一組SQL語句以得到多個(gè)結(jié)果集對(duì)象并進(jìn)行處理此時(shí)使用直接得到Rowset對(duì)象的方法,不能實(shí)現(xiàn)這類任務(wù)可以通過得到一個(gè)稱為多結(jié)果集對(duì)象的IMultipleResults接口的方法來一次得到多個(gè)結(jié)果集對(duì)象循環(huán)調(diào)用IMultipleResults::GetResult可以遍歷所有的結(jié)果集MultipleResults對(duì)象原型:CoTypeTMultipleResults{[mandatory]interfaceIMultipleResults;[optional]interfaceISupportErrorInfo;}判定數(shù)據(jù)源是否支持多結(jié)果集對(duì)象并不是所有的數(shù)據(jù)源對(duì)象都支持多結(jié)果集對(duì)象即使支持多結(jié)果集對(duì)象的數(shù)據(jù)源對(duì)象也不一定支持同時(shí)打開所有的返回結(jié)果集對(duì)象中的多個(gè)這需要通過查詢數(shù)據(jù)源對(duì)象的DBPROPSET_DATASOURCEINFO屬性集中DBPROP_MULTIPLERESULTS屬性來確定該屬性為一個(gè)VT_I4(int)型的變量,它是一個(gè)按位設(shè)置的聯(lián)合值:當(dāng)DBPROPVAL_MR_SUPPORTED常量位被設(shè)定時(shí),說明數(shù)據(jù)源對(duì)象支持多結(jié)果集對(duì)象當(dāng)DBPROPVAL_MR_CONCURRENT常量位被設(shè)定時(shí),說明數(shù)據(jù)源對(duì)象支持同時(shí)打開多個(gè)返回的結(jié)果集對(duì)象,否則調(diào)用IMultipleResults::GetResult取得下一個(gè)結(jié)果集之前,必須釋放前一個(gè)結(jié)果集對(duì)象當(dāng)DBPROPVAL_MR_NOTSUPPORTED常量位被設(shè)定,說明數(shù)據(jù)源對(duì)象不支持多結(jié)果集對(duì)象這個(gè)屬性需要通過數(shù)據(jù)源對(duì)象的IDBProperties接口獲取IMultipleResults接口示例H-MultipleResults項(xiàng)目演示了如何通過MultipleResults對(duì)象處理多個(gè)結(jié)果集的例子在例子中還演示了如何判定一個(gè)數(shù)據(jù)源對(duì)象是否支持多結(jié)果集對(duì)象及接口同時(shí)還要掌握如何獲取屬性值的方法(之前主要是講設(shè)置屬性)在正式的項(xiàng)目中,當(dāng)確定數(shù)據(jù)源對(duì)象支持多結(jié)果集對(duì)象時(shí),都建議使用IMultipleResults接口來得到IRowset/IRowsetChange接口優(yōu)化SQL查詢語句效率-參數(shù)化查詢前述的數(shù)據(jù)變更操作接口從一定程度上取代了大多數(shù)數(shù)據(jù)增刪改操作的SQL語句并且改進(jìn)了效率在一些系統(tǒng)中,有些SQL查詢語句也是相對(duì)固定的(列數(shù)\條件列固定,值范圍固定,也就是一些操作界面中的簡(jiǎn)單查詢功能)并且會(huì)反復(fù)執(zhí)行這些查詢語句中,實(shí)質(zhì)發(fā)生變化的僅僅是條件子句中的常量值這樣再次執(zhí)行類似SQL語句而只是常量值不同時(shí),只需以參數(shù)方式傳入新的條件常量值即可,這稱之為參數(shù)化查詢比如下列行政區(qū)查詢:SelectK_StateCode,F_StateNameFromT_StateWhereLeft(K_StateCode,2)='11'其中條件值11是一個(gè)通過設(shè)置新值就變?yōu)橐粋€(gè)新的查詢,而其余部分基本不變對(duì)于這些相對(duì)較固定的查詢,可以使用OLEDB的參數(shù)化查詢進(jìn)行一定的優(yōu)化優(yōu)化的原理就是利用緩存SQL語句編譯的結(jié)果——執(zhí)行計(jì)劃的方式來跳過高昂代價(jià)的編譯過程(數(shù)據(jù)庫(kù)內(nèi)部也會(huì)這樣做)參數(shù)化查詢操作步驟要使用參數(shù)化查詢,就需要先用?通配符將需要參數(shù)化的條件常量值(或存儲(chǔ)過程的參數(shù)等)進(jìn)行替換然后調(diào)用ICommandPrepare::Prepare方法對(duì)帶有?通配符的查詢進(jìn)行預(yù)處理接著調(diào)用ICommandWithParameters::GetParameterInfo函數(shù)得到關(guān)于參數(shù)的詳細(xì)信息DBPARAMINFO結(jié)構(gòu)的數(shù)組(類似DBCOLUMNINFO數(shù)組)創(chuàng)建一個(gè)對(duì)應(yīng)的參數(shù)DBBINDING結(jié)構(gòu)數(shù)組并計(jì)算參數(shù)需要的緩沖大小調(diào)用IAccessor::CreateAccessor創(chuàng)建參數(shù)訪問器為參數(shù)分配緩沖,設(shè)置合適的參數(shù)后準(zhǔn)備DBPARAMS結(jié)構(gòu)體調(diào)用ICommand::Execute并傳入DBPARAMS結(jié)構(gòu)指針得到返回結(jié)果參數(shù)化查詢的注意事項(xiàng)使用?通配符指定參數(shù)時(shí),只能用?代替所有的常量位置而不能用?來代替字段名,表名,存儲(chǔ)過程名等數(shù)據(jù)源對(duì)象名稱用?通配符指代條件子句的常量后,一般返回的DBPARAMINFO中的參數(shù)長(zhǎng)度是?這個(gè)符號(hào)的長(zhǎng)度并不是對(duì)應(yīng)的條件字段的長(zhǎng)度,所以在綁定時(shí)需要自行指定實(shí)際參數(shù)的長(zhǎng)度參數(shù)化查詢的例子I-PrepareAndParam項(xiàng)目演示了使用參數(shù)化查詢編程的方法在正式項(xiàng)目中,固定條件的簡(jiǎn)單查詢,都建議采用參數(shù)化查詢的方式來實(shí)現(xiàn)存儲(chǔ)過程調(diào)用和輸入輸出參數(shù)在數(shù)據(jù)庫(kù)中,除了常見的表/索引/視圖等對(duì)象外,還有一類非常重要的對(duì)象:存儲(chǔ)過程因此掌握存儲(chǔ)過程的調(diào)用方法也是很重要的數(shù)據(jù)庫(kù)編程技能調(diào)用存儲(chǔ)過程一般使用參數(shù)化查詢的方法對(duì)于存儲(chǔ)過程來說,有些參數(shù)不但是像函數(shù)參數(shù)那樣傳入,更有一些參數(shù)需要傳出同時(shí)存儲(chǔ)過程還可能返回一個(gè)或多個(gè)結(jié)果集不能將存儲(chǔ)過程返回的結(jié)果集等同于存儲(chǔ)過程的返回值因此調(diào)用存儲(chǔ)過程的參數(shù)化查詢要比一般的參數(shù)化查詢復(fù)雜些輸出參數(shù)在綁定參數(shù)時(shí)指定DBBINDING結(jié)構(gòu)的eParamIO為DBPARAMIO_OUTPUT值(可以用|運(yùn)算符連接多個(gè)標(biāo)志從而使該參數(shù)即可輸入也可輸出)當(dāng)需要得到存儲(chǔ)過程的返回值時(shí),可以像下面這樣明確在SQL中指定返回值的參數(shù)化占位符WCHAR*wCmdString=L"{?=callmyProc(?,?)}";一般返回值只能是輸出參數(shù),不接受任何輸入而輸出參數(shù)也可以作為輸入?yún)?shù)使用當(dāng)參數(shù)被正確綁定并提供正確值之后,存儲(chǔ)過程被執(zhí)行對(duì)于有返回結(jié)果集的存儲(chǔ)過程來說,如果返回的結(jié)果集對(duì)象的接口不被釋放之前,輸出參數(shù)的值是不會(huì)回寫到緩沖中這主要是因?yàn)檫@些數(shù)據(jù)由數(shù)據(jù)提供者返回時(shí)是按照流的模式返回的,而結(jié)果集數(shù)據(jù)流在輸出參數(shù)及返回值之前提供,所以沒有釋放結(jié)果集對(duì)象接口時(shí),數(shù)據(jù)提供者不會(huì)接著提供輸出的任何值因此編程時(shí)需要注意的是,在關(guān)閉結(jié)果集對(duì)象接口前不要釋放為傳遞參數(shù)而提供的緩沖區(qū),直到確認(rèn)接收到了輸出參數(shù)的值之后再釋放存儲(chǔ)過程調(diào)用及輸入輸出參數(shù)例子J-InputOutputParams項(xiàng)目演示了使用參數(shù)化查詢的方法調(diào)用存儲(chǔ)過程并接收輸出參數(shù)值和返回值的例子枚舉數(shù)據(jù)源注意觀察前面一些例子程序中的彈出OLEDB鏈接對(duì)話框的程序可以發(fā)現(xiàn)該對(duì)話框中有發(fā)現(xiàn)數(shù)據(jù)源的功能比如:能夠輕松枚舉出當(dāng)前系統(tǒng)中可用的全部OLEDB數(shù)據(jù)源提供者,同時(shí)還可以枚舉出能夠連接的SQLServer數(shù)據(jù)庫(kù)的實(shí)例其實(shí)這個(gè)能力也是OLEDB組件提供的高級(jí)功能之一——數(shù)據(jù)源枚舉數(shù)據(jù)源枚舉對(duì)象枚舉對(duì)象用于搜尋可用的數(shù)據(jù)源和其它的枚舉對(duì)象(層次式)。如果客戶沒有指定所使用的上層枚舉對(duì)象,則可以使用頂層枚舉對(duì)象來枚舉可用的OLEDB提供程序枚舉對(duì)象一般通過搜尋注冊(cè)表來發(fā)現(xiàn)相應(yīng)的數(shù)據(jù)源。該對(duì)象原型如下:CoTypeTEnumerator{[mandatory]IParseDisplayName;[mandatory]ISourcesRowset;[optional]IDBInitialize;[optional]IDBProperties;[optional]ISupportErrorInfo;}頂層枚舉對(duì)象的獲得和遍歷要利用數(shù)據(jù)源枚舉功能,第一個(gè)需要得到的枚舉對(duì)象就是頂層枚舉對(duì)象,或者稱之為根枚舉器Windows系統(tǒng)默認(rèn)的OLEDB根枚舉器對(duì)象的CLSID是:CLSID_OLEDB_ENUMERATOR頂層枚舉器對(duì)象可以使用標(biāo)準(zhǔn)COM接口創(chuàng)建方法創(chuàng)建之后可以利用ISourcesRowset接口的GetSourcesRowset方法得到一個(gè)所有OLEDB提供程序信息組成的結(jié)果集對(duì)象接著可以根據(jù)結(jié)果集中的行類型判定是否是一個(gè)子枚舉對(duì)象或數(shù)據(jù)源對(duì)象等若是子枚舉對(duì)象就可以利用名字對(duì)象(moniker)的方法創(chuàng)建一個(gè)新的子枚舉對(duì)象(進(jìn)而得到子枚舉對(duì)象的子枚舉對(duì)象或數(shù)據(jù)源實(shí)例信息)若是數(shù)據(jù)源對(duì)象就可以利用名字對(duì)象(moniker)方法創(chuàng)建一個(gè)對(duì)應(yīng)的數(shù)據(jù)源對(duì)象OLEDB數(shù)據(jù)源提供者結(jié)果集字段名稱類型最大長(zhǎng)度含義描述SOURCES_NAMEDBTYPE_WSTR128枚舉對(duì)象或數(shù)據(jù)源名稱SOURCES_PARSENAMEDBTYPE_WSTR128可以傳遞給IParseDisplayName接口并得到一個(gè)moniker對(duì)象的字符串(枚舉對(duì)象或數(shù)據(jù)源的moniker)SOURCES_DESCRIPTIONDBTYPE_WSTR128枚舉對(duì)象或數(shù)據(jù)源的描述SOURCES_TYPEDBTYPE_UI22BYTEs枚舉對(duì)象或?qū)嵗念愋?有下列值:DBSOURCETYPE_BINDER(=4)-URLDBSOURCETYPE_DATASOURCE_MDP(=3)-OLAP提供者DBSOURCETYPE_DATASOURCE_TDP(=1)-關(guān)系型或表格型數(shù)據(jù)源DBSOURCETYPE_ENUMERATOR(=2)-子枚舉對(duì)象SOURCES_ISPARENTDBTYPE_BOOL2BYTEs是否父枚舉器IMoniker接口及COM對(duì)象的另類創(chuàng)建法名字對(duì)象(moniker)的創(chuàng)建方法,是一種標(biāo)準(zhǔn)的以名字解析方法創(chuàng)建一個(gè)COM對(duì)象及接口的方法比CoCreateInstance等方法要高級(jí)其原理就是通過一個(gè)全局唯一的COM對(duì)象的名稱來創(chuàng)建一個(gè)COM對(duì)象及指定的接口其內(nèi)部實(shí)際還是利用了從對(duì)象名稱(moniker)獲得對(duì)象的CLSID并最終創(chuàng)建COM對(duì)象的方法在數(shù)據(jù)源枚舉具體應(yīng)用中:先得到數(shù)據(jù)源枚舉對(duì)象的IParseDisplayName接口(一個(gè)標(biāo)準(zhǔn)的COM接口,專用于支持moniker式的COM對(duì)象創(chuàng)建)接著調(diào)用IParseDisplayName::ParseDisplayName并傳遞SOURCES_PARSENAME字段的值,得到IMoniker接口最后調(diào)用BindMoniker(標(biāo)準(zhǔn)COM庫(kù)API)傳遞IMoniker指針,并指定需要?jiǎng)?chuàng)建的子枚舉對(duì)象或數(shù)據(jù)源對(duì)象的相應(yīng)接口ID數(shù)據(jù)源枚舉示例K-EnumDataSource項(xiàng)目演示了通過OLEDB枚舉對(duì)象枚舉系統(tǒng)中的OLEDB提供程序的方法例子中還演示了如何進(jìn)一步利用SQLServer的實(shí)例枚舉器進(jìn)一步枚舉出SQLServer實(shí)例的方法同時(shí)例子中重點(diǎn)演示了Moniker名字對(duì)象創(chuàng)建的標(biāo)準(zhǔn)COM方法直接打開表對(duì)象之前講過,并不是所有的數(shù)據(jù)源提供者都支持命令對(duì)象但都必須支持結(jié)果集對(duì)象雖然這樣的數(shù)據(jù)源很少見,但是通過直接打開結(jié)果集的方法可以繞開SQL命令的執(zhí)行過程,而直接高效的打開一些數(shù)據(jù)源的對(duì)象其中最重要的方法就是打開表對(duì)象打開表對(duì)象的步驟方法:聲明一個(gè)DBID結(jié)構(gòu)體對(duì)象為結(jié)構(gòu)體對(duì)象的eKind對(duì)象種類字段賦值DBKIND_NAME為結(jié)構(gòu)體對(duì)象的uName.pwszName字段賦值表名稱調(diào)用IOpenRowset::OpenRowset函數(shù)傳遞DBID結(jié)構(gòu)體對(duì)象指針,并得到相應(yīng)的結(jié)果集對(duì)象指定的接口指針此方法也可用于打開其它的對(duì)象,如:視圖等此方法也可設(shè)置打開的結(jié)果集屬性,并可以直接要求對(duì)表等對(duì)象進(jìn)行數(shù)據(jù)增刪改操作無SQL直接操作表示例L-Table項(xiàng)目演示了直接打開表結(jié)果集并申請(qǐng)進(jìn)行增刪改操作以及要求延遲更新特性特別注意例子中沒有使用SQL語句數(shù)據(jù)庫(kù)結(jié)構(gòu)分析一般的數(shù)據(jù)庫(kù)編程任務(wù)中,數(shù)據(jù)庫(kù)中的結(jié)構(gòu)是事先確定并告知開發(fā)人員的而有些任務(wù)中,數(shù)據(jù)庫(kù)結(jié)構(gòu)可能事先是無法知道的,比如一些通用目的數(shù)據(jù)庫(kù)軟件:報(bào)表系統(tǒng)/數(shù)據(jù)庫(kù)應(yīng)用開發(fā)系統(tǒng)/分析系統(tǒng)等此時(shí)就需要這些軟件具備能夠解析數(shù)據(jù)庫(kù)結(jié)構(gòu)的能力,如:確定數(shù)據(jù)庫(kù)中有多少表/每個(gè)表有哪些字段/每個(gè)字段的數(shù)據(jù)類型等等在OLEDB中提供了專門的接口用于解析數(shù)據(jù)庫(kù)結(jié)構(gòu)的接口和相應(yīng)機(jī)制——架構(gòu)結(jié)果集(schemarowset)架構(gòu)結(jié)果集在OLEDB模型定義的會(huì)話事務(wù)對(duì)象中有一個(gè)可選接口IDBSchemaRowset用于得到一個(gè)數(shù)據(jù)庫(kù)中的架構(gòu)結(jié)果集每個(gè)架構(gòu)結(jié)果集都有一個(gè)對(duì)應(yīng)的架構(gòu)GUID,以標(biāo)明是那類對(duì)象的架構(gòu)信息在OLEDB中定義了一些標(biāo)準(zhǔn)的數(shù)據(jù)庫(kù)必須支持的架構(gòu)結(jié)果集的ID常量(只列舉了常用的一些):TABLE_CONSTRAINTSTABLE_PRIVILEGESTABLESTABLES_INFOCOLUMNSCONSTRAINT_COLUMN_USAGECONSTRAINT_TABLE_USAGEVIEW_COLUMN_USAGEVIEWSVIEW_TABLE_USAGEPROCEDURE_COLUMNSPROCEDURE_PARAMETERSPROCEDURES架構(gòu)結(jié)果集全集信息獲取一般除了標(biāo)準(zhǔn)的架構(gòu)結(jié)果集ID外,很多數(shù)據(jù)源提供者還提供了各自擴(kuò)展的架構(gòu)結(jié)果集ID,用于展示擴(kuò)展的對(duì)象架構(gòu)信息為方便"啟發(fā)式"數(shù)據(jù)庫(kù)編程,IDBSchemaRowset接口特別提供了GetSchemas方法用于得到所有架構(gòu)結(jié)果集ID的方法架構(gòu)結(jié)果集的過濾每個(gè)架構(gòu)結(jié)果集的前幾列幾乎被定義為是一樣的這樣做主要是為了方便利用一些相似的條件來過濾架構(gòu)結(jié)果集中的信息因?yàn)橐粋€(gè)數(shù)據(jù)庫(kù)中結(jié)構(gòu)信息往往是非常復(fù)雜和豐富的,而應(yīng)用程序?qū)嶋H關(guān)心的只是其中的一部分,所以這樣就要求能夠按條件過濾出所需要的結(jié)構(gòu)信息比如:在SQLServer中,不加任何過濾時(shí),架構(gòu)結(jié)果集會(huì)返回所有數(shù)據(jù)庫(kù)中所有對(duì)象的信息(表,視圖,存儲(chǔ)過程以及相關(guān)字段等等),這時(shí)就可以利用數(shù)據(jù)庫(kù)(Catalog)所有者,表名等來進(jìn)行必要的過濾使用架構(gòu)結(jié)果集的步驟1、創(chuàng)建數(shù)據(jù)源對(duì)象2、創(chuàng)建會(huì)話事務(wù)對(duì)象3、獲得IDBSchemaRowset接口4、調(diào)用IDBSchemaRowset::GetSchemas獲取數(shù)據(jù)源支持的所有架構(gòu)結(jié)果集的ID/指定已知的架構(gòu)結(jié)果集ID5、準(zhǔn)備過濾條件VARIANT型數(shù)組變量6、調(diào)用IDBSchemaRowset::GetRowset,傳入架構(gòu)結(jié)果集ID以及準(zhǔn)備的過濾條件,獲取架構(gòu)結(jié)果集對(duì)象的IRowset接口7、讀取IRowset中的數(shù)據(jù),獲取信息架構(gòu)結(jié)果集調(diào)用示例M-Schema項(xiàng)目演示了如何使用架構(gòu)結(jié)果集對(duì)象獲取數(shù)據(jù)源相關(guān)信息的方法BLOB型數(shù)據(jù)現(xiàn)代的數(shù)據(jù)庫(kù)系統(tǒng)中除了提供一些標(biāo)準(zhǔn)的通用的數(shù)據(jù)類型支持外,大多數(shù)還支持一種稱之為BLOB型的數(shù)據(jù)BLOB:binarylargeobjects(BLOBs),就是大二進(jìn)制對(duì)象類型通常一些類似于文檔、圖片、音頻等本身體積較大的數(shù)據(jù)都可以存儲(chǔ)進(jìn)數(shù)據(jù)庫(kù)中通過對(duì)這些類型數(shù)據(jù)表的擴(kuò)展信息字段,可以方便的檢索和管理這些文件比如:為圖片添加簡(jiǎn)單說明信息,拍攝日期等信息字段就可以按照簡(jiǎn)介、日期等來檢索圖片在SQLServer中常見的BLOB型數(shù)據(jù)類型為:text、ntext、image、nvarchar(max)、varchar(max)、varbinary(max)等BLOB型數(shù)據(jù)一般數(shù)據(jù)庫(kù)系統(tǒng)中對(duì)于BLOB型數(shù)據(jù)的存放都有特殊的處理方式因此通過OLEDB接口來獲取和存儲(chǔ)這些數(shù)據(jù)也需要一些特殊的方法:通過設(shè)置綁定結(jié)構(gòu)時(shí)指定一些特殊的值,最終指定獲取BLOB型數(shù)據(jù)的一個(gè)ISequentialStream接口指針最終通過調(diào)用ISequentialStream接口的函數(shù)讀取或?qū)懭隑OLB型數(shù)據(jù)的值BLOB列的判定以下兩個(gè)條件之一成立時(shí),即可判定列為BLOB型:1、pColumnInfo[iCol].wType==DBTYPE_IUNKNOWN列類型判定2、pColumnInfo[iCol].dwFlags&DBCOLUMNFLAGS_ISLONG列標(biāo)志判定BLOB型數(shù)據(jù)的綁定綁定BLOB型數(shù)據(jù)時(shí)也有特殊的要求:1、綁定結(jié)構(gòu)的cbMaxLen要設(shè)置為0;2、設(shè)置wType=DBTYPE_IUNKNOWN;3、為pObject指針分配內(nèi)存pObject=(DBOBJECT*)GRS_CALLOC(sizeof(DBOBJECT));4、指定pObject結(jié)構(gòu)的成員pObject->iid=IID_ISequentialStream;pObject->dwFlags=STGM_READ;5、為行緩沖長(zhǎng)度加上一個(gè)ISequentialStream*指針的長(zhǎng)度dwOffset+=sizeof(ISequentialStream*)通過上述綁定結(jié)構(gòu)的特殊賦值可以看出,綁定BLOB列其實(shí)質(zhì)是最終獲取一個(gè)ISequentialStream接口指針BLOB數(shù)據(jù)獲取根據(jù)前述BLOB列的特殊綁定結(jié)構(gòu)設(shè)定,最終獲取到的列數(shù)據(jù)將是一個(gè)ISequentialStream*類型的接口指針調(diào)用ISequentialStream::Read可以讀取到BLOB列中的數(shù)據(jù)而BLOB數(shù)據(jù)最終真正的長(zhǎng)度存儲(chǔ)在綁定時(shí)指定的數(shù)據(jù)長(zhǎng)度內(nèi)存偏移處,這與普通列的長(zhǎng)度存放返回方式是一樣的一般BLOB型數(shù)據(jù)的長(zhǎng)度都比較長(zhǎng),因此在讀取分配緩沖時(shí)需要注意方法和策略,如果太長(zhǎng)就分段讀取多列BLOB數(shù)據(jù)的處理當(dāng)一個(gè)數(shù)據(jù)表中有多個(gè)BLOB型數(shù)據(jù)列時(shí),并不是所有的數(shù)據(jù)源對(duì)象都支持在一個(gè)訪問器中一次訪問所有這樣的列(因?yàn)檫@樣的列本身極耗費(fèi)資源)要判定一個(gè)數(shù)據(jù)源對(duì)象是否支持在一個(gè)訪問器中讀取多個(gè)BLOB列的特性,需要判定數(shù)據(jù)源對(duì)象的DBPROP_MULTIPLESTORAGEOBJECTS屬性該屬性屬于DBPROPSET_ROWSET屬性集,是一個(gè)只讀屬性再獲得結(jié)果集對(duì)象后,通過IRowsetInfo接口的GetProperties函數(shù)得到該

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論