版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
第22講數(shù)據(jù)庫訪問接口OLEDB+ADO掌握數(shù)據(jù)世界大門的鑰匙講師:GamebabyRockSun第22講主要內(nèi)容(1)1.數(shù)據(jù)庫訪問接口簡介(ODBC、OLEDB、ADO、ADO.Net)2.數(shù)據(jù)庫系統(tǒng)簡介3.OLEDB簡介4.MSDAC介紹和幫助獲取5.OLEDB編程基礎(chǔ)6.數(shù)據(jù)源對象和連接數(shù)據(jù)庫7.會話對象和創(chuàng)建會話事務(wù)對象8.命令對象及接口9.結(jié)果集對象及接口10.列信息獲取和動態(tài)綁定11.數(shù)據(jù)增刪改操作及延遲提交12.多結(jié)果集對象13.SQL預處理和參數(shù)化查詢14.輸入輸出參數(shù)和存儲過程調(diào)用15.數(shù)據(jù)源枚舉16.無SQL直接操作表第22講主要內(nèi)容(2)17.數(shù)據(jù)源動態(tài)結(jié)構(gòu)分析和架構(gòu)結(jié)果集18.BLOB字段插入和讀取操作19.結(jié)構(gòu)化綁定(靜態(tài)綁定)20.日期時間型數(shù)據(jù)列處理21.數(shù)據(jù)類型轉(zhuǎn)換對象22.數(shù)據(jù)變更通知23.結(jié)果集查找操作及IRowsetFind接口24.出錯信息處理25.使用事務(wù)處理26.ATL中的OLEDB模版及用法27.ADO組件及用法28.ADO和OLEDB混合編程29.使用ADO調(diào)用存儲過程30.GRSLib中數(shù)據(jù)庫訪問組件的添加引言數(shù)據(jù)庫是計算機應用系統(tǒng)中的一種專門管理數(shù)據(jù)資源的系統(tǒng).數(shù)據(jù)有多種形式:文字、數(shù)碼、符號、圖形、圖像以及聲音等.數(shù)據(jù)是所有計算機系統(tǒng)所要處理的對象.數(shù)據(jù)庫系統(tǒng)不從具體的應用程序出發(fā),而是立足于數(shù)據(jù)本身的管理,它將所有數(shù)據(jù)保存在數(shù)據(jù)庫中,進行科學的組織,并借助于數(shù)據(jù)庫管理系統(tǒng),以它為中介,與各種應用程序或應用系統(tǒng)接口,使之能方便地使用數(shù)據(jù)庫中的數(shù)據(jù).目前幾乎所有的軟件系統(tǒng)都需要與數(shù)據(jù)庫系統(tǒng)打交道(包括操作系統(tǒng)),有些系統(tǒng)更是以數(shù)據(jù)庫作為核心,因此掌握數(shù)據(jù)庫系統(tǒng)的使用方法以及數(shù)據(jù)庫系統(tǒng)編程接口的使用方法是程序員非常重要的基本技能之一.認識數(shù)據(jù)庫系統(tǒng)數(shù)據(jù)庫系統(tǒng)是一個實際可運行的存儲、維護和應用系統(tǒng)提供數(shù)據(jù)的軟件系統(tǒng),是存儲介質(zhì)、處理對象和管理系統(tǒng)的集合體.它通常由軟件、數(shù)據(jù)庫和數(shù)據(jù)管理員組成.其軟件主要包括操作系統(tǒng)、各種宿主語言、實用程序以及數(shù)據(jù)庫管理系統(tǒng).數(shù)據(jù)庫由數(shù)據(jù)庫管理系統(tǒng)統(tǒng)一管理,數(shù)據(jù)的插入、修改和檢索均要通過數(shù)據(jù)庫管理系統(tǒng)進行.數(shù)據(jù)管理員負責創(chuàng)建、監(jiān)控和維護整個數(shù)據(jù)庫,使數(shù)據(jù)能被任何有權(quán)使用的人有效使用.數(shù)據(jù)庫管理員一般是由業(yè)務(wù)水平較高、資歷較深的人員擔任.數(shù)據(jù)庫系統(tǒng)的個體含義是指一個具體的數(shù)據(jù)庫管理系統(tǒng)軟件和用它建立起來的數(shù)據(jù)庫;它的學科含義是指研究、開發(fā)、建立、維護和應用數(shù)據(jù)庫系統(tǒng)所涉及的理論、方法、技術(shù)所構(gòu)成的學科.在這一含義下,數(shù)據(jù)庫系統(tǒng)是軟件研究領(lǐng)域的一個重要分支,常稱為數(shù)據(jù)庫領(lǐng)域.典型的數(shù)據(jù)庫系統(tǒng)示意圖接口1數(shù)據(jù)庫存儲DBMS接口2應用1應用2應用3常見的DBMS系統(tǒng)Oracle:甲骨文公司出品Sybase:Sybase公司出品Informix、DB2:IBM公司出品MicrosoftSQLServer、MicrosoftAccess、VisualFoxPro:Microsoft出品MySql:瑞典MySqlAB公司出品(開源,被Sun收購后并入Oracle公司)主要的數(shù)據(jù)庫編程組件ODBCDAORDOADOADO.NETOLEDB(本課程中將主要講解OLEDB和ADO接口的編程方法,其它接口因已不常用只做簡要介紹)ODBCODBC(Open
Database
Connectivity
開放數(shù)據(jù)庫互連):是微軟公司開放服務(wù)結(jié)構(gòu)(WOSA,WindowsOpen
Services
Architecture)中有關(guān)數(shù)據(jù)庫的一個組成部分,它建立了一組規(guī)范,并提供了一組對數(shù)據(jù)庫訪問的標準API(應用程序編程接口).這些API利用SQL來完成其大部分任務(wù).ODBC本身也提供了對SQL語言的支持,用戶可以直接將SQL語句送給ODBC.(出現(xiàn)的最早,但不總是萬能.現(xiàn)已很少使用.)DAODAO:數(shù)據(jù)訪問對象是用來顯露了Microsoft
Jet數(shù)據(jù)庫引擎(最早是給Microsoft
Access
所使用,現(xiàn)在已經(jīng)支持其它數(shù)據(jù)庫),并允許開發(fā)者通過ODBC直接連接到其他數(shù)據(jù)庫一樣,直接連接到Access表.DAO最適用于單系統(tǒng)應用程序或在小范圍本地分布使用.其內(nèi)部已經(jīng)對Jet數(shù)據(jù)庫的訪問進行了加速優(yōu)化,而且其使用起來也是很方便的.所以如果數(shù)據(jù)庫是Access數(shù)據(jù)庫且是本地使用的話,建議使用這種訪問方式.(應用專一性,現(xiàn)已很少使用.)RDORDO(Remote
Data
Objects):遠程數(shù)據(jù)對象是一個到ODBC的、面向?qū)ο蟮臄?shù)據(jù)訪問接口,它同易于使用的DAO
style組合在一起,提供了一個接口,形式上展示出所有ODBC的底層功能和靈活性.盡管RDO在很好地訪問Jet或ISAM數(shù)據(jù)庫方面受到限制,而且它只能通過現(xiàn)存的ODBC驅(qū)動程序來訪問關(guān)系數(shù)據(jù)庫.RDO已被證明是許多SQL
Server、Oracle以及其他大型關(guān)系數(shù)據(jù)庫開發(fā)者經(jīng)常選用的最佳接口.RDO提供了用來訪問存儲過程和復雜結(jié)果集的更多和更復雜的對象、屬性,以及方法.(無疑是構(gòu)建在ODBC基礎(chǔ)上的,現(xiàn)已很少使用.)ADOADO(ActiveX
Data
Object)是DAO/RDO的后繼產(chǎn)物.ADO2.0在功能上與RDO更相似,而且一般來說,在這兩種模型之間有一種相似的映射關(guān)系.ADO"擴展"了DAO和RDO所使用的對象模型,這意味著它包含較少的對象、更多的屬性、方法(和參數(shù)),以及事件.作為最新的數(shù)據(jù)庫訪問模式,ADO的使用也是簡單易用,所以微軟已經(jīng)明確表示今后把重點放在ADO上,對DAO/RDO不再作升級,所以ADO已經(jīng)成為了當前數(shù)據(jù)庫開發(fā)的主流.ADO涉及的數(shù)據(jù)存儲有DSN(數(shù)據(jù)源名稱)、ODBC(開放式數(shù)據(jù)連接)以及OLEDB三種方式.(可以說是對ODBC,OLEDB這些系統(tǒng)級的編程接口的匯接,并對DAO,RDO這些應用級的編程接口的升級,主要基于OLEDB擴展)ADO.NETADO.NET的名稱起源于ADO(ActiveXDataObjects),這是一個廣泛的類組,用于在以往的Microsoft技術(shù)中訪問數(shù)據(jù).之所以使用ADO.NET名稱,是因為Microsoft希望表明,這是在.NET編程環(huán)境中優(yōu)先使用的數(shù)據(jù)訪問接口.它提供了平臺互用性和可伸縮的數(shù)據(jù)訪問.ADO.NET增強了對非連接編程模式的支持,并支持RICHXML由于傳送的數(shù)據(jù)都是XML格式的,因此任何能夠讀取XML格式的應用程序都可以進行數(shù)據(jù)處理.事實上,接受數(shù)據(jù)的組件不一定要是ADO.NET組件,它可以是基于一個MicrosoftVisualStudio的解決方案,也可以是任何運行在其它平臺上的任何應用程序.
ADO.NET是一組用于和數(shù)據(jù)源進行交互的面向?qū)ο箢悗?通常情況下,數(shù)據(jù)源是數(shù)據(jù)庫,但它同樣也能夠是文本文件、Excel表格或者XML文件.OLEDBOLEDB是Microsoft的一個戰(zhàn)略性系統(tǒng)級編程接口,用于管理整個組織內(nèi)的數(shù)據(jù).OLEDB是建立在ODBC功能之上的一個基于COM的開放規(guī)范.ODBC是為訪問關(guān)系型數(shù)據(jù)庫而專門開發(fā)的,OLEDB則用于訪問關(guān)系型和非關(guān)系型信息源,例如主機ISAM/VSAM和層次數(shù)據(jù)庫,電子郵件和文件系統(tǒng)存儲,文本、圖形和地理數(shù)據(jù)以及自定義業(yè)務(wù)對象.(甚至可以訪問URL)
OLEDB定義了一組COM接口,對各種數(shù)據(jù)庫管理系統(tǒng)服務(wù)進行封裝,并允許創(chuàng)建軟件組件,實現(xiàn)這些服務(wù).OLEDB組件包括數(shù)據(jù)提供程序(包含和表現(xiàn)數(shù)據(jù))、數(shù)據(jù)使用者(使用數(shù)據(jù))和服務(wù)組件(處理和傳送數(shù)據(jù),例如,查詢處理器和游標引擎).OLEDB接口有助于平滑地集成組件,這樣,OLEDB組件廠商就可以快速地向市場提供高質(zhì)量OLEDB組件.此外,OLEDB包含了一個連接ODBC的“橋梁”,對現(xiàn)用的各種ODBC關(guān)系型數(shù)據(jù)庫驅(qū)動程序提供一貫的支持.(不是簡單的取代ODBC,而是兼容ODBC)數(shù)據(jù)庫編程組件間的關(guān)系示意圖OLEDB編程基本概念在OLEDB中將接口兩端的軟件稱為數(shù)據(jù)提供者和數(shù)據(jù)消費者(使用者).在OLEDB中,不但要考慮使用數(shù)據(jù)的一方,還要考慮提供數(shù)據(jù)的一方,比如各種數(shù)據(jù)庫系統(tǒng)幾乎都提供了自己的OLEDB接口.從本質(zhì)上說,OLEDB其實就是一個標準的數(shù)據(jù)庫與應用系統(tǒng)間的數(shù)據(jù)標準交換接口,它的好處就是高效,通用和靈活.如果是數(shù)據(jù)提供的一方,在OLEDB中就稱之為數(shù)據(jù)提供者(簡單理解為各種DBMS),如果是使用數(shù)據(jù)的一方,那么就稱之為數(shù)據(jù)消費者(一般就是開發(fā)的使用數(shù)據(jù)庫作為支持的軟件系統(tǒng)).在本教程中將主要學習數(shù)據(jù)消費者接口(也即數(shù)據(jù)使用端的詳細編程).MSDAC簡介和幫助獲取MDAC(MicrosoftDataAccessComponents)是微軟數(shù)據(jù)庫訪問組件很多Windows中已經(jīng)存在了MDAC在MDAC中主要有三種組件:(1)ADO(2)OLEDB(3)ODBCOLEDB編程基本框架和步驟OLEDB組件對象和接口OLEDB基于COM規(guī)范打造的并擴展了一些自有的特殊性規(guī)則;(OLEDB是基于COM的擴展規(guī)范)其中對象接口被劃分為強制支持的(mandatory)和可選支持的(optional)OLEDB對象除支持OLEDB標準接口外,各個數(shù)據(jù)提供者廠商(如MSSQLServer,ORACLE等)還可提供額外的接口,用于特殊的功能支持特殊接口需要查閱相關(guān)OLEDB接口的文檔,除SQLServer的特殊接口外,其余的特殊接口在MSDN中一般沒有進一步描述)在OLEDB中,有4個主要對象:數(shù)據(jù)源(DataSource)會話和事務(wù)(Session)命令(Command)結(jié)果集(Rowset)DataSourceObject數(shù)據(jù)源對象代表到數(shù)據(jù)庫的一個鏈接是使用或鏈接數(shù)據(jù)源需要創(chuàng)建的第一個對象數(shù)據(jù)源對象提供下列接口:CoTypeTDataSource{[mandatory]interfaceIDBCreateSession;[mandatory]interfaceIDBInitialize;[mandatory]interfaceIDBProperties;[mandatory]interfaceIPersist;[optional]interfaceIConnectionPointContainer;[optional]interfaceIDBAsynchStatus;[optional]interfaceIDBDataSourceAdmin;[optional]interfaceIDBInfo;[optional]interfaceIPersistFile;[optional]interfaceISupportErrorInfo;}以上任何接口被創(chuàng)建時,可以認為隱藏的DataSource對象已創(chuàng)建,并可以得到其它的接口數(shù)據(jù)源對象數(shù)據(jù)源對象一般需要完成的主要功能:進行數(shù)據(jù)庫身份驗證,即通過屬性給數(shù)據(jù)源提供用戶名/密碼/具體數(shù)據(jù)庫等信息以便數(shù)據(jù)源進行身份合法性驗證在數(shù)據(jù)提供者內(nèi)部,還要為每個鏈接準備適當?shù)木彌_,網(wǎng)絡(luò)鏈接等等資源同時數(shù)據(jù)源對象還需要設(shè)置和提供很多更高級的關(guān)于各個數(shù)據(jù)庫的詳細選項(比如SQLServer的鏈接超時值等)所有這些選項都被OLEDB規(guī)范為稱為屬性集和屬性的概念OLEDB屬性集和屬性數(shù)據(jù)使用者通過設(shè)置屬性值以請求特定的對象行為.例如:使用者使用屬性以指定要由行集公開的接口.數(shù)據(jù)使用者獲得屬性值,以確定對象(比如行集、會話或數(shù)據(jù)源對象)的功能.每個屬性都有值、類型、說明和讀/寫屬性,對于行集屬性,還有一個用于指示是否可以逐列應用它的指示器.屬性由一個GUID和一個表示屬性ID的整數(shù)進行標識.屬性集是所有具有相同GUID的一組屬性.除了預定義的OLEDB屬性集以外,一些特定DBMS的OLEDB接口如SQLServerNativeClientOLEDB訪問接口還實現(xiàn)了特定于訪問接口的屬性集和屬性集中的屬性.每個屬性屬于一個或多個屬性組.屬性組是應用于特定對象的所有屬性所形成的組.屬性組包括初始化屬性組、數(shù)據(jù)源屬性組、會話屬性組、行集屬性組、表屬性組和列屬性組等等.在每個這樣的屬性組中都有屬性.屬性值的使用確定要設(shè)置值的屬性.確定包含所標識屬性的屬性集.分配DBPROPSET結(jié)構(gòu)數(shù)組,每個標識的屬性集一個.為每個屬性集分配DBPROP結(jié)構(gòu)數(shù)組.每個數(shù)組中的元素個數(shù)是屬于該屬性集的屬性(在步驟1中標識)的個數(shù).填充每個屬性的DBPROP結(jié)構(gòu).在每個屬性集的DBPROPSET結(jié)構(gòu)中,填充信息(屬性集GUID、元素的計數(shù)以及對應的DBPROP數(shù)組的指針).調(diào)用方法以設(shè)置屬性,并傳遞DBPROPSET結(jié)構(gòu)的計數(shù)和數(shù)組.為什么不用COM接口的屬性?從關(guān)于屬性和屬性集合的描述上可以看出,其實這些屬性完全可以暴露為相應COM接口中的屬性但是為什么OLEDB中沒這樣做呢?其實主要是因為以下幾個原因:1、屬性值通常具有分組特性,用COM接口來表示需要使用多個不同的接口來包容這些屬性,為接口定義的簡潔化帶來麻煩2、屬性的數(shù)量龐大,但不都是經(jīng)常使用或必須的,因此全部暴露出來為實現(xiàn)和調(diào)用帶來麻煩3、除了OLEDB標準定義的屬性外,各個具體OLEDB提供者還有各自專門的屬性集和屬性,且有些還經(jīng)常變動,這些用COM接口來暴露的話,將導致COM接口定義不斷變化的問題,違背COM接口一經(jīng)定義就不再變動的原則(破壞了COM的基本規(guī)則)這給我們提供了一個現(xiàn)實的利用COM框架進行設(shè)計時如何優(yōu)化屬性類接口設(shè)計的范例創(chuàng)建數(shù)據(jù)源對象根據(jù)COM規(guī)范,可以通過調(diào)用標準COM函數(shù)CoCreateInstance創(chuàng)建任意數(shù)據(jù)源對象的接口的方法來創(chuàng)建一個數(shù)據(jù)源對象:IDBInitialize*pIDBInitialize=NULL;CoCreateInstance(CLSID_MSDASQL,NULL,CLSCTX_INPROC_SERVER,IID_IDBInitialize,(void**)&pIDBInitialize);上面的代碼中,CLSID_MSDASQL就是真正創(chuàng)建的數(shù)據(jù)源對象的CLSID,還可以使用別的數(shù)據(jù)提供者提供的數(shù)據(jù)源對象的CLSID這也說明數(shù)據(jù)源對象的實例可以有很多種,實際中幾乎每種DBMS對應的OLEDB接口都提供了專門的數(shù)據(jù)源對象雖然例子中只是創(chuàng)建了一個IDBInitialize的接口,但是編碼中要有實際已創(chuàng)建了一個數(shù)據(jù)源對象的認識數(shù)據(jù)源對象的屬性數(shù)據(jù)源對象的屬性集合GUID是DBPROPSET_DBINIT其中包含下列較常用的屬性(ID):DBPROP_INIT_DATASOURCE數(shù)據(jù)源實例名DBPROP_INIT_CATALOG 目錄名(對SQLServer來說是具體的數(shù)據(jù)庫名稱,對Oracle來說無意義)DBPROP_AUTH_USERID 用戶名DBPROP_AUTH_PASSWORD 密碼連接到數(shù)據(jù)源創(chuàng)建了IDBInitialize接口之后,雖然有了數(shù)據(jù)源對象,但是并不表示已經(jīng)連接到了數(shù)據(jù)源上之后還需要設(shè)置前述的幾個基本屬性給數(shù)據(jù)源對象,以便數(shù)據(jù)提供者驗明正身,提供鏈接并準備緩沖首先需要從IDBInitialize接口Query出IDBProperties接口其次要準備GUID為DBPROPSET_DBINIT的DBPROPSET結(jié)構(gòu)體和前述幾個屬性及對應值組成的DBPROP數(shù)組調(diào)用IDBProperties接口的SetProperties方法設(shè)置上述屬性最后調(diào)用IDBInitialize的Initialize方法鏈接到數(shù)據(jù)庫斷開連接調(diào)用IDBInitialize的Uninitialize方法斷開與數(shù)據(jù)庫的連接調(diào)用IDBInitialize的Release方法釋放數(shù)據(jù)源對象IDBInitialize接口示例1-IDBInitialize項目演示了使用前述方法連接到數(shù)據(jù)庫的例子例子中還展示了基本的屬性和屬性集使用方法IDBInitialize接口的困境雖然前面的方法很簡單便可以連接到指定的數(shù)據(jù)源上,但是這種簡單的方法有些無法克服的問題首先就是這種創(chuàng)建方法本質(zhì)上是依托于標準COM接口的創(chuàng)建方法,因此無法在標準COM創(chuàng)建的基礎(chǔ)上做很多擴展初始化的工作這導致這種方法雖然創(chuàng)建了數(shù)據(jù)源對象,但是對象特有的一些功能無法使用(比如后期需要IRowsetFind等高級接口功能時可能無法獲得IRowsetFind接口)為此OLEDB2.0之后又特別提供了兩個接口IDataInitialize和IDBPromptInitialize作為數(shù)據(jù)源創(chuàng)建對象來創(chuàng)建數(shù)據(jù)源對象這樣就繞開了直接使用標準COM方法創(chuàng)建數(shù)據(jù)源對象帶來的問題IDBPromptInitialize接口IDBPromptInitialize為創(chuàng)建OLEDB數(shù)據(jù)源對象提供了一個可視化的對話框通過這個對話框,用戶可以快速選定OLEDB具體的提供者以及快速設(shè)置包括數(shù)據(jù)源/用戶/密碼等屬性以及其它擴展屬性通過調(diào)用該接口的PromptDataSource方法即可彈出OLEDB數(shù)據(jù)源對話框并且最終返回IDBInitialize接口IDataInitialize接口IDataInitialize接口除了可以用來替代CoCreateInstance來創(chuàng)建數(shù)據(jù)源對象之外還提供了豐富的功能使用IDataInitialize接口可以通過一個連接字符串的方式連接到指定的數(shù)據(jù)源通過從IDBPromptInitialize接口Query出IDataInitialize接口可以直接得到一個連接字符串使用數(shù)據(jù)源對象創(chuàng)建對象示例A-DataSource項目演示了使用前述兩個接口來創(chuàng)建數(shù)據(jù)源對象的示例在實際的OLEDB代碼中,都推薦使用該示例中的方法來創(chuàng)建數(shù)據(jù)源對象和連接Session事務(wù)對象事務(wù)是一種對數(shù)據(jù)源的一系列更新進行分組或批處理以便當所有更新都成功時同時提交這些更新,或者如果任何一個更新失敗則不提交任何更新并且回滾整個事務(wù)的方法.事務(wù)確保了數(shù)據(jù)源上數(shù)據(jù)的完整性.OLEDB通過下列三種方法支持事務(wù):ITransactionLocal::StartTransactionITransaction::CommitITransaction::Abort會話和事務(wù)對象接口OLEDB中會話和事務(wù)對象標準接口定義如下: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;}會話和事務(wù)單個數(shù)據(jù)源對象可以創(chuàng)建一個或多個會話對象,每個會話對象都可以在給定時間位于事務(wù)范圍內(nèi)或范圍外.如果會話未進入事務(wù),則在該會話中對數(shù)據(jù)存儲區(qū)所做的所有工作都會在每個方法調(diào)用后立即提交.(這有時稱為自動提交模式或隱式模式.)如果會話進入事務(wù),則在該會話中對數(shù)據(jù)存儲區(qū)所做的所有工作都成為該事務(wù)的組成部分并作為單個單元提交或中止.(這有時稱為手動提交模式.)事務(wù)支持是特定于提供程序的.如果所使用的提供程序支持事務(wù),則支持ITransaction和ITransactionLocal的會話對象便可以進入簡單(即非嵌套)的事務(wù).啟動和結(jié)束事務(wù)在使用者的行集合對象中調(diào)用StartTransaction、Commit和Abort方法.調(diào)用ITransactionLocal::StartTransaction將啟動一個新的本地事務(wù).啟動事務(wù)后,由隨后的操作強制進行的任何更改只有在提交該事務(wù)時才會實際應用于數(shù)據(jù)存儲區(qū).調(diào)用ITransaction::Commit或ITransaction::Abort將結(jié)束該事務(wù).Commit使該事務(wù)范圍內(nèi)的所有更改都應用于數(shù)據(jù)存儲區(qū).Abort使該事務(wù)范圍內(nèi)的所有更改都被取消,并且數(shù)據(jù)存儲區(qū)將保持在啟動該事務(wù)之前的狀態(tài).嵌套事務(wù)如果在會話中已經(jīng)存在一個活動事務(wù)時啟動一個新的本地事務(wù),則發(fā)生嵌套事務(wù).新的事務(wù)將作為當前事務(wù)下的嵌套事務(wù)啟動.如果提供程序不支持嵌套事務(wù),則在會話中已經(jīng)存在一個活動事務(wù)時調(diào)用StartTransaction將返回XACT_E_XTIONEXISTS.分布式事務(wù)分布式事務(wù)是用于更新分布式數(shù)據(jù)(即位于一個以上網(wǎng)絡(luò)計算機系統(tǒng)上的數(shù)據(jù))的事務(wù).支持分布式事務(wù)的提供者支持ITransactionJoin接口會話事務(wù)對象特殊擴展接口IDBSchemaRowset:數(shù)據(jù)庫結(jié)構(gòu)解析IIndexDefinition:索引定義ITableCreation:表創(chuàng)建ITableDefinition:表定義ITableDefinitionWithConstraints:帶約束的表定義IAlterIndex:索引變更IAlterTable:表變更事務(wù)屬性和事務(wù)隔離級別在SQL-92中定義了事務(wù)的隔離級別,在OLEDB中可以通過ISessionProperties接口以屬性的方式來設(shè)置事務(wù)的隔離級別在OLEDB中Session對象僅有一個屬性集合DBPROPSET_SESSION,該集合中也只有一個屬性DBPROP_SESS_AUTOCOMMITISOLEVELS用來設(shè)置當前會話的事務(wù)隔離級別另外可以通過調(diào)用ITransactionLocal::StartTransaction時指定isoLevel參數(shù)的方式來設(shè)定新建事務(wù)的隔離級別(關(guān)于事務(wù)隔離級別的概念可以查閱相關(guān)的標準文檔,維基百科中有標準規(guī)范的描述)會話事務(wù)對象的創(chuàng)建在擁有了數(shù)據(jù)源對象之后,通過已有接口Query出IDBCreateSession接口然后調(diào)用IDBCreateSession::CreateSession方法創(chuàng)建一個Session對象的接口,也即創(chuàng)建一個新的Session對象需要注意的是一個數(shù)據(jù)源對象可以用來創(chuàng)建多個Session對象及接口,創(chuàng)建多少個一般沒有限制這里要注意的是不能用CoCreateInstance標準方法來創(chuàng)建Session對象及接口這種創(chuàng)建新的對象及接口的方式也是對COM規(guī)范本身的擴展,是一種基于COM設(shè)計系統(tǒng)時的擴展設(shè)計模式默認的Session對象的事務(wù)隔離級別是自動提交級別(為進一步確定可調(diào)用ISessionProperties::GetProperties來檢查)為了能夠正常進行后續(xù)的處理任務(wù),一般應用中至少應創(chuàng)建一個Session對象(很多簡單應用中創(chuàng)建一個也就夠用了)Session對象創(chuàng)建示例B-SessionObject項目演示了如何創(chuàng)建一個會話事務(wù)對象在例子中特意演示了通過查詢接口的方式判斷數(shù)據(jù)提供者都支持那些功能Command對象對于像數(shù)據(jù)庫這類數(shù)據(jù)源,操作的最好方法就是使用SQL語句在OLEDB中對執(zhí)行SQL語句提供了完整的支持,實現(xiàn)這一功能最重要的對象就是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對象狀態(tài)根據(jù)SQL語句被設(shè)置和處理的過程,一個Command對象可以有以下4個狀態(tài):Initial:初始狀態(tài)Unprepared:未預處理狀態(tài)(已設(shè)置SQL,但沒有預處理)Prepared:已預處理狀態(tài)Executed:已執(zhí)行狀態(tài)以上4個狀態(tài)可以相互轉(zhuǎn)化,已預處理狀態(tài)有時可以被跳過可以直接執(zhí)行的SQL語句可以通過Command對象直接執(zhí)行,而無需預處理Command對象的創(chuàng)建再擁有了Session對象之后就可以創(chuàng)建Command對象了一般通過Query出Session對象的IDBCreateCommand接口后,就可以創(chuàng)建Command對象了需要注意的是IDBCreateCommand接口是個可選接口,這是因為并不是所有的OLEDB提供者都支持命令處理(比如SQL語句處理),所以該接口為可選項在使用Command對象時,一定要先確定能夠從Session對象得到IDBCreateCommand接口即使一個數(shù)據(jù)提供者不支持Command對象,依然可以通過直接打開數(shù)據(jù)對象的方法來操作其數(shù)據(jù),這在后面講結(jié)果集對象時介紹最后需要記住的是一個Session對象可以創(chuàng)建多個Command對象Command對象創(chuàng)建示例C-CommandObject項目演示了通過Session對象創(chuàng)建Command對象的例子例子中還通過查詢所有Command對象接口的方式來確定數(shù)據(jù)提供者支持的Command對象的功能執(zhí)行SQL命令創(chuàng)建Command對象的真實目的就是為了處理和執(zhí)行一個SQL命令從另一個角度說如果能夠方便的執(zhí)行SQL語句了,那么意味著實際已可以對數(shù)據(jù)源進行任何方式的處理但是既然有了OLEDB接口,也可以執(zhí)行SQL語句,依然鼓勵某些功能還是使用OLEDB接口來進行這是因為SQL語句的執(zhí)行需要經(jīng)過解析緩沖執(zhí)行等過程,有些SQL語句還可能因為編寫問題導致效率低下,所以對于一些任務(wù)鼓勵使用OLEDB接口這種直接的編程方式來替代SQL語句的執(zhí)行,比如:數(shù)據(jù)更改,新增,刪除等等通常執(zhí)行一些SQL命令后會返回一個結(jié)果集對象,而有些SQL語句并不返回結(jié)果集對象執(zhí)行SQL命令利用Command對象執(zhí)行SQL語句時,需要先得到ICommandText接口調(diào)用ICommandText::SetCommandText設(shè)置SQL命令接著調(diào)用ICommand::Execute方法執(zhí)行該命令,并得到可能的結(jié)果集對象的接口指針(通常是IRowset*)這里要注意的是,OLEDB并沒有規(guī)定被執(zhí)行的命令必須是SQL語句,這個是數(shù)據(jù)提供者的要求,因為一般使用的是數(shù)據(jù)庫這類數(shù)據(jù)源,所以經(jīng)常使用的就是SQL語言命令因此掌握SQL語言也是對程序員的一個基本要求執(zhí)行SQL示例D-ExecuteSQL項目演示了如何利用Command對象執(zhí)行一條SQL命令的方法和過程例子還演示了如何設(shè)置Command對象的屬性執(zhí)行SQL語句而忽略結(jié)果有些情況下應用程序在執(zhí)行SQL語句時往往不需要返回的結(jié)果集,或者只是執(zhí)行一些本身并不返回任何結(jié)果集的SQL語句,此時可以像下面這樣調(diào)用即可:pICommandText->Execute(NULL,IID_NULL,NULL,NULL,NULL);Command對象的屬性與之前的DataSource對象和Session對象不同,Command對象的屬性最終并不影響Command對象自身而是作用于由執(zhí)行命令而產(chǎn)生的結(jié)果集對象這些屬性通常必須在SQL命令執(zhí)行并得到結(jié)果集之前通過ICommandProperties::SetProperties設(shè)置這些屬性的屬性集ID是DBPROPSET_ROWSET,該屬性集中有很多能夠最終影響Rowset對象的屬性這些屬性的最終行為就充分展示了OLEDB編程接口的靈活性后面的討論中講逐步介紹其中一些重要的屬性和用法結(jié)果集對象Rowset結(jié)果集對象一般是執(zhí)行SQL語句以后返回的一個代表二維結(jié)構(gòu)化數(shù)組的對象,其原型為: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é)果集對象的一般用法一般通過得到IRowset接口指針來得到結(jié)果集對象首先Query出IColumnsInfo接口通過調(diào)用IColumnsInfo::GetColumnInfo方法得到關(guān)于結(jié)果集的列的詳細信息DBCOLUMNINFO結(jié)構(gòu)的數(shù)組,包括:列序號,列名,類型,字節(jié)長度,精度,比例等通過該結(jié)構(gòu)數(shù)組,準備一個對應的DBBINDING結(jié)構(gòu)數(shù)組,并計算每行數(shù)據(jù)實際需要的緩沖大小利用DBBINDING數(shù)組和IAccessor::CreateAccessor方法創(chuàng)建一個數(shù)據(jù)訪問器并得到句柄HACCESSOR調(diào)用IRowset::GetNextRow遍歷行指針到下一行,第一次調(diào)用就是指向第一行,并得到行句柄HROW調(diào)用IRowset::GetData傳入準備好的行緩沖內(nèi)存指針,以及之前創(chuàng)建的訪問器HACCESSOR句柄和HROW句柄最終行數(shù)據(jù)就被放置到了指定的緩沖中循環(huán)調(diào)用GetNextRow和GetData即可遍歷整個二維結(jié)果集結(jié)果集對象示例E-RowsetObject項目演示了如何從Command對象得到一個Rowset對象,并通過QueryRowset對象的所有接口的方式來了解具體的屬性對Rowset對象接口的影響F-Binding項目演示了如何通過簡單的綁定得到并遍歷整個結(jié)果集并顯示出最終的數(shù)據(jù)列信息的獲取取得結(jié)果集對象后,緊接著的操作一般就是獲取結(jié)果集的結(jié)構(gòu)信息,也就是獲取結(jié)果集的列信息(有些材料中稱為字段信息)要獲取列信息,就需要QueryInterface出結(jié)果集對象的IColumnsInfo接口,并調(diào)用IColumnsInfo::GetColumnInfo方法獲得一個稱為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字段中存放的是列名稱,一般是一個UNICODE字符串pTypeInfo目前還未使用iOrdinal是列序號,一般從1開始,當該序號為0時是用于指定特殊列(后面會有專門討論)dwFlags是一個按位設(shè)置的關(guān)于該列的標志信息(其位值在DBCOLUMNFLAGS枚舉中定義)ulColumnSize是該列的最大字節(jié)大小(根據(jù)具體列數(shù)據(jù)類型的不同其具體含義有差異)wType表示該列的類型(其值由DBTYPEENUM枚舉值定義)bPrecision指出該列的精度(數(shù)值型有意義)bScale指出該列的比例columnid指出了該列信息在數(shù)據(jù)庫字典表中存儲的ID從列信息到綁定信息有了二維結(jié)果集的列信息之后,就可以著手讀取二維結(jié)果集數(shù)據(jù)的工作了但是在OLEDB中有了列信息并不表示可以直接開始讀取行數(shù)據(jù)了這中間還需要執(zhí)行一步稱為綁定的操作綁定通常需要執(zhí)行兩個步驟:1、根據(jù)前面的列信息建立綁定結(jié)構(gòu)數(shù)組(DBBINDING);2、使用綁定結(jié)構(gòu)數(shù)組創(chuàng)建訪問器(HACCESSOR);之所以這樣做的原因是:1、不是所有的數(shù)據(jù)類型都是能夠被使用程序直接支持的;2、有時一行數(shù)據(jù)不能完全讀取到內(nèi)存中;3、不是所有的訪問器都是為了讀取數(shù)據(jù);4、使用綁定可以靈活的安排行數(shù)據(jù)在內(nèi)存中的排放方式;綁定過程是OLEDB接口較之其它接口最具特色和最靈活的地方數(shù)據(jù)綁定詳解(1)對綁定最簡單的理解:數(shù)據(jù)使用者安排得到數(shù)據(jù)的內(nèi)存擺放方式,并將這一方式告訴數(shù)據(jù)提供者,讓其按要求將數(shù)據(jù)擺放到指定的內(nèi)存緩存中為了這個目的,就需要創(chuàng)建一個被稱作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)這個結(jié)構(gòu)與DBCOLUMNINFO結(jié)構(gòu)很相似,實際它的字段大多可以直接使用DBCOLUMNINFO對應字段進行賦值但是二者字段的用途確是完全不同的:1、DBCOLUMNINFO是數(shù)據(jù)提供者給使用者的信息,它是固定的,對相同的查詢來說,列總是相同的,因此數(shù)據(jù)提供者返回的DBCOLUMNINFO數(shù)組也是固定的.2、DBBINDING是作為數(shù)據(jù)消費者創(chuàng)建之后給數(shù)據(jù)提供者的一個結(jié)構(gòu)數(shù)組,它的內(nèi)容則由調(diào)用者來完全控制,通過這個結(jié)構(gòu)可以指定數(shù)據(jù)提供者最終將數(shù)據(jù)擺放成調(diào)用者指定的格式,并進行指定的數(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項目代碼,最終搞懂BINDING原理和用法執(zhí)行SQL與使用OLEDB編程接口比較數(shù)據(jù)存儲SQL語句SQL編譯器OLEDB組件數(shù)據(jù)庫核心引擎(可執(zhí)行組件)執(zhí)行計劃(緩存)應用程序執(zhí)行SQL與使用OLEDB編程接口比較從前圖可以看出執(zhí)行SQL語句來操作數(shù)據(jù)庫數(shù)據(jù)的方式必須要經(jīng)歷一個耗時的SQL編譯階段在大規(guī)模應用中,使用SQL語句來進行數(shù)據(jù)庫的操作將付出高昂的代價(如果再考慮多客戶端并發(fā)操作時優(yōu)化所有SQL的代價更高昂)比如向數(shù)據(jù)庫使用Insert語句插入成千上萬條記錄時,效率問題表現(xiàn)更突出而使用OLEDB對應功能接口使用編程的方式,則明顯直接和高效的多(相當于直接操作數(shù)據(jù)庫引擎)對于數(shù)據(jù)的增刪改操作建議使用OLEDB相應編程接口進行對于數(shù)據(jù)的復雜動態(tài)查詢不做此要求數(shù)據(jù)的變更操作通??梢詧?zhí)行SQL語句后,對數(shù)據(jù)的增刪改操作就可以利用SQL語句的方式來進行但是執(zhí)行SQL的效率和性能在大規(guī)模應用中很不近人意此時可以使用OLEDB中Rowset對象的專用更新接口進行編程的方式進行數(shù)據(jù)增刪改操作數(shù)據(jù)修改的主要功能接口是IRowsetChangeIRowsetChange::DeleteRows刪除行IRowsetChange::InsertRow 插入新行IRowsetChange::SetData 修改行中列數(shù)據(jù)通過該接口可以直接對數(shù)據(jù)進行無SQL式的增刪改操作打開IRowsetChange接口在默認情況下打開的Rowset對象是不支持增刪改操作的,這主要是因為數(shù)據(jù)源為了效能等方面的考慮要對結(jié)果集進行變更操作時必須通過設(shè)置屬性的方式顯式的打開IRowsetChange接口需要設(shè)置的屬性ID是DBPROP_UPDATABILITY,屬于DBPROPSET_ROWSET屬性集該屬性有3個可按位或設(shè)置的候選值:DBPROPVAL_UP_CHANGE:打開SetDataDBPROPVAL_UP_DELETE:打開DeleteRowsDBPROPVAL_UP_INSERT:打開InsertRow之所以將增刪改功能屬性分開,也是為了給數(shù)據(jù)提供者有機會進行精細化的性能優(yōu)化考慮打開IRowsetChange接口的特殊要求如果需要對結(jié)果集進行增刪改操作,那么除了通過設(shè)置屬性打開IRowsetChange接口外還需要注意一個特殊的地方,即必須使用IRowsetChange替代IRowset等接口,作為創(chuàng)建并打開結(jié)果集對象的第一個接口比如在使用ICommand::Execute函數(shù)時就需要像下面這樣調(diào)用:pICommand->Execute(NULL,IID_IRowsetChange,NULL
,NULL,(IUnknown**)&pIRowsetChange);這個要求與一般的OLEDB對象接口創(chuàng)建原則有差異數(shù)據(jù)修改的模式一般調(diào)用IRowsetChange接口的增刪改方法對數(shù)據(jù)做出的修改都會立即反映到數(shù)據(jù)源數(shù)據(jù)庫中(稱為立即模式)對于一般的應用來說這雖然繞開了全部使用SQL語句的低效模式,但是有以下問題:1-修改立刻反映到數(shù)據(jù)源中,不利于數(shù)據(jù)完整性維護和數(shù)據(jù)安全性;2-如果是網(wǎng)絡(luò)數(shù)據(jù)庫模式,這會形成很多小規(guī)模的網(wǎng)絡(luò)包傳輸,造成網(wǎng)絡(luò)利用效率低下;因此OLEDB中還提供了另一種模式——延遲更新模式延遲更新模式延遲更新模式本質(zhì)上提供了一種對所有修改進行緩沖并最終一次性提交的機制(注意不要理解為事務(wù)方式)該模式有如下優(yōu)點:1-當多個客戶端都在修改同一數(shù)據(jù)源數(shù)據(jù)時,可以有機會對已作出的修改通知給別的客戶端2-可以合并對一行數(shù)據(jù)中的多列數(shù)據(jù)的修改并一次性提交到數(shù)據(jù)源中3-網(wǎng)絡(luò)模式下,可以將多個修改同一數(shù)據(jù)表(或別的對象)的多個操作形成的包合并成一個大包傳輸,提高網(wǎng)絡(luò)傳輸效率4-當更改不合適時,可以調(diào)用IRowsetUpdate::Undo選擇放棄修改打開延遲更新接口要使用延遲更新特性,必須申請打開結(jié)果集對象的IRowsetUpdate接口與IRowsetChange接口類似該接口也需要通過設(shè)置特殊屬性DBPROP_IRowsetUpdate來打開,該屬性也屬于DBPROPSET_ROWSET屬性集如果需要同時緩沖修改/刪除和新增的新行時,還需要額外打開DBPROP_CANHOLDROWS屬性這兩個屬性都是VARIANT_BOOL型變量,屬性值設(shè)置為VARIANT_TRUE即表示要求打開這兩個屬性要打開延遲更新接口,必須先打開IRowsetChange接口使用OLEDB更新數(shù)據(jù)時的細節(jié)問題如果打開了DBPROP_CANHOLDROWS屬性,為了方便管理,一般數(shù)據(jù)提供者都會為返回的結(jié)果集額外生成一個第0列,作為數(shù)據(jù)消費者和數(shù)據(jù)提供者直接對照行號的憑據(jù)通常該列為INT型值,并且由數(shù)據(jù)提供者來維護,數(shù)據(jù)消費者要對數(shù)據(jù)進行增刪改操作時一般不能對該列進行修改操作(即該列對于數(shù)據(jù)消費者來說是只讀列)但此列可以作為一個行序號讀取并顯示出來,此時需要考慮的問題是創(chuàng)建至少兩個行訪問器,一個綁定第0列作為讀取使用,另一個不綁定第0列,作為變更數(shù)據(jù)專用訪問器一般情況下可以通過檢測返回結(jié)果集中的列信息中的標志字段來確定哪些列可以進行變更,哪些列是只讀列等標志來創(chuàng)建多個不同用途的行訪問器延遲更新行狀態(tài)遷移數(shù)據(jù)更新示例G-DelayUpdate項目演示了如何使用結(jié)果集對象的變更接口來進行變更操作的例子,并且使用了延遲更新特性使用延遲更新模式,可以開發(fā)出類似PowerBuild中的數(shù)據(jù)窗口式的控件來提高開發(fā)效率多結(jié)果集接口IMultipleResults有些任務(wù)中,需要傳遞一組SQL語句以得到多個結(jié)果集對象并進行處理此時使用直接得到Rowset對象的方法,不能實現(xiàn)這類任務(wù)可以通過得到一個稱為多結(jié)果集對象的IMultipleResults接口的方法來一次得到多個結(jié)果集對象循環(huán)調(diào)用IMultipleResults::GetResult可以遍歷所有的結(jié)果集MultipleResults對象原型:CoTypeTMultipleResults{[mandatory]interfaceIMultipleResults;[optional]interfaceISupportErrorInfo;}判定數(shù)據(jù)源是否支持多結(jié)果集對象并不是所有的數(shù)據(jù)源對象都支持多結(jié)果集對象即使支持多結(jié)果集對象的數(shù)據(jù)源對象也不一定支持同時打開所有的返回結(jié)果集對象中的多個這需要通過查詢數(shù)據(jù)源對象的DBPROPSET_DATASOURCEINFO屬性集中DBPROP_MULTIPLERESULTS屬性來確定該屬性為一個VT_I4(int)型的變量,它是一個按位設(shè)置的聯(lián)合值:當DBPROPVAL_MR_SUPPORTED常量位被設(shè)定時,說明數(shù)據(jù)源對象支持多結(jié)果集對象當DBPROPVAL_MR_CONCURRENT常量位被設(shè)定時,說明數(shù)據(jù)源對象支持同時打開多個返回的結(jié)果集對象,否則調(diào)用IMultipleResults::GetResult取得下一個結(jié)果集之前,必須釋放前一個結(jié)果集對象當DBPROPVAL_MR_NOTSUPPORTED常量位被設(shè)定,說明數(shù)據(jù)源對象不支持多結(jié)果集對象這個屬性需要通過數(shù)據(jù)源對象的IDBProperties接口獲取IMultipleResults接口示例H-MultipleResults項目演示了如何通過MultipleResults對象處理多個結(jié)果集的例子在例子中還演示了如何判定一個數(shù)據(jù)源對象是否支持多結(jié)果集對象及接口同時還要掌握如何獲取屬性值的方法(之前主要是講設(shè)置屬性)在正式的項目中,當確定數(shù)據(jù)源對象支持多結(jié)果集對象時,都建議使用IMultipleResults接口來得到IRowset/IRowsetChange接口優(yōu)化SQL查詢語句效率-參數(shù)化查詢前述的數(shù)據(jù)變更操作接口從一定程度上取代了大多數(shù)數(shù)據(jù)增刪改操作的SQL語句并且改進了效率在一些系統(tǒng)中,有些SQL查詢語句也是相對固定的(列數(shù)\條件列固定,值范圍固定,也就是一些操作界面中的簡單查詢功能)并且會反復執(zhí)行這些查詢語句中,實質(zhì)發(fā)生變化的僅僅是條件子句中的常量值這樣再次執(zhí)行類似SQL語句而只是常量值不同時,只需以參數(shù)方式傳入新的條件常量值即可,這稱之為參數(shù)化查詢比如下列行政區(qū)查詢:SelectK_StateCode,F_StateNameFromT_StateWhereLeft(K_StateCode,2)='11'其中條件值11是一個通過設(shè)置新值就變?yōu)橐粋€新的查詢,而其余部分基本不變對于這些相對較固定的查詢,可以使用OLEDB的參數(shù)化查詢進行一定的優(yōu)化優(yōu)化的原理就是利用緩存SQL語句編譯的結(jié)果——執(zhí)行計劃的方式來跳過高昂代價的編譯過程(數(shù)據(jù)庫內(nèi)部也會這樣做)參數(shù)化查詢操作步驟要使用參數(shù)化查詢,就需要先用?通配符將需要參數(shù)化的條件常量值(或存儲過程的參數(shù)等)進行替換然后調(diào)用ICommandPrepare::Prepare方法對帶有?通配符的查詢進行預處理接著調(diào)用ICommandWithParameters::GetParameterInfo函數(shù)得到關(guān)于參數(shù)的詳細信息DBPARAMINFO結(jié)構(gòu)的數(shù)組(類似DBCOLUMNINFO數(shù)組)創(chuàng)建一個對應的參數(shù)DBBINDING結(jié)構(gòu)數(shù)組并計算參數(shù)需要的緩沖大小調(diào)用IAccessor::CreateAccessor創(chuàng)建參數(shù)訪問器為參數(shù)分配緩沖,設(shè)置合適的參數(shù)后準備DBPARAMS結(jié)構(gòu)體調(diào)用ICommand::Execute并傳入DBPARAMS結(jié)構(gòu)指針得到返回結(jié)果參數(shù)化查詢的注意事項使用?通配符指定參數(shù)時,只能用?代替所有的常量位置而不能用?來代替字段名,表名,存儲過程名等數(shù)據(jù)源對象名稱用?通配符指代條件子句的常量后,一般返回的DBPARAMINFO中的參數(shù)長度是?這個符號的長度并不是對應的條件字段的長度,所以在綁定時需要自行指定實際參數(shù)的長度參數(shù)化查詢的例子I-PrepareAndParam項目演示了使用參數(shù)化查詢編程的方法在正式項目中,固定條件的簡單查詢,都建議采用參數(shù)化查詢的方式來實現(xiàn)存儲過程調(diào)用和輸入輸出參數(shù)在數(shù)據(jù)庫中,除了常見的表/索引/視圖等對象外,還有一類非常重要的對象:存儲過程因此掌握存儲過程的調(diào)用方法也是很重要的數(shù)據(jù)庫編程技能調(diào)用存儲過程一般使用參數(shù)化查詢的方法對于存儲過程來說,有些參數(shù)不但是像函數(shù)參數(shù)那樣傳入,更有一些參數(shù)需要傳出同時存儲過程還可能返回一個或多個結(jié)果集不能將存儲過程返回的結(jié)果集等同于存儲過程的返回值因此調(diào)用存儲過程的參數(shù)化查詢要比一般的參數(shù)化查詢復雜些輸出參數(shù)在綁定參數(shù)時指定DBBINDING結(jié)構(gòu)的eParamIO為DBPARAMIO_OUTPUT值(可以用|運算符連接多個標志從而使該參數(shù)即可輸入也可輸出)當需要得到存儲過程的返回值時,可以像下面這樣明確在SQL中指定返回值的參數(shù)化占位符WCHAR*wCmdString=L"{?=callmyProc(?,?)}";一般返回值只能是輸出參數(shù),不接受任何輸入而輸出參數(shù)也可以作為輸入?yún)?shù)使用當參數(shù)被正確綁定并提供正確值之后,存儲過程被執(zhí)行對于有返回結(jié)果集的存儲過程來說,如果返回的結(jié)果集對象的接口不被釋放之前,輸出參數(shù)的值是不會回寫到緩沖中這主要是因為這些數(shù)據(jù)由數(shù)據(jù)提供者返回時是按照流的模式返回的,而結(jié)果集數(shù)據(jù)流在輸出參數(shù)及返回值之前提供,所以沒有釋放結(jié)果集對象接口時,數(shù)據(jù)提供者不會接著提供輸出的任何值因此編程時需要注意的是,在關(guān)閉結(jié)果集對象接口前不要釋放為傳遞參數(shù)而提供的緩沖區(qū),直到確認接收到了輸出參數(shù)的值之后再釋放存儲過程調(diào)用及輸入輸出參數(shù)例子J-InputOutputParams項目演示了使用參數(shù)化查詢的方法調(diào)用存儲過程并接收輸出參數(shù)值和返回值的例子枚舉數(shù)據(jù)源注意觀察前面一些例子程序中的彈出OLEDB鏈接對話框的程序可以發(fā)現(xiàn)該對話框中有發(fā)現(xiàn)數(shù)據(jù)源的功能比如:能夠輕松枚舉出當前系統(tǒng)中可用的全部OLEDB數(shù)據(jù)源提供者,同時還可以枚舉出能夠連接的SQLServer數(shù)據(jù)庫的實例其實這個能力也是OLEDB組件提供的高級功能之一——數(shù)據(jù)源枚舉數(shù)據(jù)源枚舉對象枚舉對象用于搜尋可用的數(shù)據(jù)源和其它的枚舉對象(層次式)。如果客戶沒有指定所使用的上層枚舉對象,則可以使用頂層枚舉對象來枚舉可用的OLEDB提供程序枚舉對象一般通過搜尋注冊表來發(fā)現(xiàn)相應的數(shù)據(jù)源。該對象原型如下:CoTypeTEnumerator{[mandatory]IParseDisplayName;[mandatory]ISourcesRowset;[optional]IDBInitialize;[optional]IDBProperties;[optional]ISupportErrorInfo;}頂層枚舉對象的獲得和遍歷要利用數(shù)據(jù)源枚舉功能,第一個需要得到的枚舉對象就是頂層枚舉對象,或者稱之為根枚舉器Windows系統(tǒng)默認的OLEDB根枚舉器對象的CLSID是:CLSID_OLEDB_ENUMERATOR頂層枚舉器對象可以使用標準COM接口創(chuàng)建方法創(chuàng)建之后可以利用ISourcesRowset接口的GetSourcesRowset方法得到一個所有OLEDB提供程序信息組成的結(jié)果集對象接著可以根據(jù)結(jié)果集中的行類型判定是否是一個子枚舉對象或數(shù)據(jù)源對象等若是子枚舉對象就可以利用名字對象(moniker)的方法創(chuàng)建一個新的子枚舉對象(進而得到子枚舉對象的子枚舉對象或數(shù)據(jù)源實例信息)若是數(shù)據(jù)源對象就可以利用名字對象(moniker)方法創(chuàng)建一個對應的數(shù)據(jù)源對象OLEDB數(shù)據(jù)源提供者結(jié)果集字段名稱類型最大長度含義描述SOURCES_NAMEDBTYPE_WSTR128枚舉對象或數(shù)據(jù)源名稱SOURCES_PARSENAMEDBTYPE_WSTR128可以傳遞給IParseDisplayName接口并得到一個moniker對象的字符串(枚舉對象或數(shù)據(jù)源的moniker)SOURCES_DESCRIPTIONDBTYPE_WSTR128枚舉對象或數(shù)據(jù)源的描述SOURCES_TYPEDBTYPE_UI22BYTEs枚舉對象或?qū)嵗念愋?有下列值:DBSOURCETYPE_BINDER(=4)-URLDBSOURCETYPE_DATASOURCE_MDP(=3)-OLAP提供者DBSOURCETYPE_DATASOURCE_TDP(=1)-關(guān)系型或表格型數(shù)據(jù)源DBSOURCETYPE_ENUMERATOR(=2)-子枚舉對象SOURCES_ISPARENTDBTYPE_BOOL2BYTEs是否父枚舉器IMoniker接口及COM對象的另類創(chuàng)建法名字對象(moniker)的創(chuàng)建方法,是一種標準的以名字解析方法創(chuàng)建一個COM對象及接口的方法比CoCreateInstance等方法要高級其原理就是通過一個全局唯一的COM對象的名稱來創(chuàng)建一個COM對象及指定的接口其內(nèi)部實際還是利用了從對象名稱(moniker)獲得對象的CLSID并最終創(chuàng)建COM對象的方法在數(shù)據(jù)源枚舉具體應用中:先得到數(shù)據(jù)源枚舉對象的IParseDisplayName接口(一個標準的COM接口,專用于支持moniker式的COM對象創(chuàng)建)接著調(diào)用IParseDisplayName::ParseDisplayName并傳遞SOURCES_PARSENAME字段的值,得到IMoniker接口最后調(diào)用BindMoniker(標準COM庫API)傳遞IMoniker指針,并指定需要創(chuàng)建的子枚舉對象或數(shù)據(jù)源對象的相應接口ID數(shù)據(jù)源枚舉示例K-EnumDataSource項目演示了通過OLEDB枚舉對象枚舉系統(tǒng)中的OLEDB提供程序的方法例子中還演示了如何進一步利用SQLServer的實例枚舉器進一步枚舉出SQLServer實例的方法同時例子中重點演示了Moniker名字對象創(chuàng)建的標準COM方法直接打開表對象之前講過,并不是所有的數(shù)據(jù)源提供者都支持命令對象但都必須支持結(jié)果集對象雖然這樣的數(shù)據(jù)源很少見,但是通過直接打開結(jié)果集的方法可以繞開SQL命令的執(zhí)行過程,而直接高效的打開一些數(shù)據(jù)源的對象其中最重要的方法就是打開表對象打開表對象的步驟方法:聲明一個DBID結(jié)構(gòu)體對象為結(jié)構(gòu)體對象的eKind對象種類字段賦值DBKIND_NAME為結(jié)構(gòu)體對象的uName.pwszName字段賦值表名稱調(diào)用IOpenRowset::OpenRowset函數(shù)傳遞DBID結(jié)構(gòu)體對象指針,并得到相應的結(jié)果集對象指定的接口指針此方法也可用于打開其它的對象,如:視圖等此方法也可設(shè)置打開的結(jié)果集屬性,并可以直接要求對表等對象進行數(shù)據(jù)增刪改操作無SQL直接操作表示例L-Table項目演示了直接打開表結(jié)果集并申請進行增刪改操作以及要求延遲更新特性特別注意例子中沒有使用SQL語句數(shù)據(jù)庫結(jié)構(gòu)分析一般的數(shù)據(jù)庫編程任務(wù)中,數(shù)據(jù)庫中的結(jié)構(gòu)是事先確定并告知開發(fā)人員的而有些任務(wù)中,數(shù)據(jù)庫結(jié)構(gòu)可能事先是無法知道的,比如一些通用目的數(shù)據(jù)庫軟件:報表系統(tǒng)/數(shù)據(jù)庫應用開發(fā)系統(tǒng)/分析系統(tǒng)等此時就需要這些軟件具備能夠解析數(shù)據(jù)庫結(jié)構(gòu)的能力,如:確定數(shù)據(jù)庫中有多少表/每個表有哪些字段/每個字段的數(shù)據(jù)類型等等在OLEDB中提供了專門的接口用于解析數(shù)據(jù)庫結(jié)構(gòu)的接口和相應機制——架構(gòu)結(jié)果集(schemarowset)架構(gòu)結(jié)果集在OLEDB模型定義的會話事務(wù)對象中有一個可選接口IDBSchemaRowset用于得到一個數(shù)據(jù)庫中的架構(gòu)結(jié)果集每個架構(gòu)結(jié)果集都有一個對應的架構(gòu)GUID,以標明是那類對象的架構(gòu)信息在OLEDB中定義了一些標準的數(shù)據(jù)庫必須支持的架構(gòu)結(jié)果集的ID常量(只列舉了常用的一些):TABLE_CONSTRAINTSTABLE_PRIVILEGESTABLESTABLES_INFOCOLUMNSCONSTRAINT_COLUMN_USAGECONSTRAINT_TABLE_USAGEVIEW_COLUMN_USAGEVIEWSVIEW_TABLE_USAGEPROCEDURE_COLUMNSPROCEDURE_PARAMETERSPROCEDURES架構(gòu)結(jié)果集全集信息獲取一般除了標準的架構(gòu)結(jié)果集ID外,很多數(shù)據(jù)源提供者還提供了各自擴展的架構(gòu)結(jié)果集ID,用于展示擴展的對象架構(gòu)信息為方便"啟發(fā)式"數(shù)據(jù)庫編程,IDBSchemaRowset接口特別提供了GetSchemas方法用于得到所有架構(gòu)結(jié)果集ID的方法架構(gòu)結(jié)果集的過濾每個架構(gòu)結(jié)果集的前幾列幾乎被定義為是一樣的這樣做主要是為了方便利用一些相似的條件來過濾架構(gòu)結(jié)果集中的信息因為一個數(shù)據(jù)庫中結(jié)構(gòu)信息往往是非常復雜和豐富的,而應用程序?qū)嶋H關(guān)心的只是其中的一部分,所以這樣就要求能夠按條件過濾出所需要的結(jié)構(gòu)信息比如:在SQLServer中,不加任何過濾時,架構(gòu)結(jié)果集會返回所有數(shù)據(jù)庫中所有對象的信息(表,視圖,存儲過程以及相關(guān)字段等等),這時就可以利用數(shù)據(jù)庫(Catalog)所有者,表名等來進行必要的過濾使用架構(gòu)結(jié)果集的步驟1、創(chuàng)建數(shù)據(jù)源對象2、創(chuàng)建會話事務(wù)對象3、獲得IDBSchemaRowset接口4、調(diào)用IDBSchemaRowset::GetSchemas獲取數(shù)據(jù)源支持的所有架構(gòu)結(jié)果集的ID/指定已知的架構(gòu)結(jié)果集ID5、準備過濾條件VARIANT型數(shù)組變量6、調(diào)用IDBSchemaRowset::GetRowset,傳入架構(gòu)結(jié)果集ID以及準備的過濾條件,獲取架構(gòu)結(jié)果集對象的IRowset接口7、讀取IRowset中的數(shù)據(jù),獲取信息架構(gòu)結(jié)果集調(diào)用示例M-Schema項目演示了如何使用架構(gòu)結(jié)果集對象獲取數(shù)據(jù)源相關(guān)信息的方法BLOB型數(shù)據(jù)現(xiàn)代的數(shù)據(jù)庫系統(tǒng)中除了提供一些標準的通用的數(shù)據(jù)類型支持外,大多數(shù)還支持一種稱之為BLOB型的數(shù)據(jù)BLOB:binarylargeobjects(BLOBs),就是大二進制對象類型通常一些類似于文檔、圖片、音頻等本身體積較大的數(shù)據(jù)都可以存儲進數(shù)據(jù)庫中通過對這些類型數(shù)據(jù)表的擴展信息字段,可以方便的檢索和管理這些文件比如:為圖片添加簡單說明信息,拍攝日期等信息字段就可以按照簡介、日期等來檢索圖片在SQLServer中常見的BLOB型數(shù)據(jù)類型為:text、ntext、image、nvarchar(max)、varchar(max)、varbinary(max)等BLOB型數(shù)據(jù)一般數(shù)據(jù)庫系統(tǒng)中對于BLOB型數(shù)據(jù)的存放都有特殊的處理方式因此通過OLEDB接口來獲取和存儲這些數(shù)據(jù)也需要一些特殊的方法:通過設(shè)置綁定結(jié)構(gòu)時指定一些特殊的值,最終指定獲取BLOB型數(shù)據(jù)的一個ISequentialStream接口指針最終通過調(diào)用ISequentialStream接口的函數(shù)讀取或?qū)懭隑OLB型數(shù)據(jù)的值BLOB列的判定以下兩個條件之一成立時,即可判定列為BLOB型:1、pColumnInfo[iCol].wType==DBTYPE_IUNKNOWN列類型判定2、pColumnInfo[iCol].dwFlags&DBCOLUMNFLAGS_ISLONG列標志判定BLOB型數(shù)據(jù)的綁定綁定BLOB型數(shù)據(jù)時也有特殊的要求: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、為行緩沖長度加上一個ISequentialStream*指針的長度dwOffset+=sizeof(ISequentialStream*)通過上述綁定結(jié)構(gòu)的特殊賦值可以看出,綁定BLOB列其實質(zhì)是最終獲取一個ISequentialStream接口指針BLOB數(shù)據(jù)獲取根據(jù)前述BLOB列的特殊綁定結(jié)構(gòu)設(shè)定,最終獲取到的列數(shù)據(jù)將是一個ISequentialStream*類型的接口指針調(diào)用ISequentialStream::Read可以讀取到BLOB列中的數(shù)據(jù)而BLOB數(shù)據(jù)最終真正的長度存儲在綁定時指定的數(shù)據(jù)長度內(nèi)存偏移處,這與普通列的長度存放返回方式是一樣的一般BLOB型數(shù)據(jù)的長度都比較長,因此在讀取分配緩沖時需要注意方法和策略,如果太長就分段讀取多列BLOB數(shù)據(jù)的處理當一個數(shù)據(jù)表中有多個BLOB型數(shù)據(jù)列時,并不是所有的數(shù)據(jù)源對象都支持在一個訪問器中一次訪問所有這樣的列(因為這樣的列本身極耗費資源)要判定一個數(shù)據(jù)源對象是否支持在一個訪問器中讀取多個BLOB列的特性,需要判定數(shù)據(jù)源對象的DBPROP_MULTIPLESTORAGEOBJECTS屬性該屬性屬于DBPROPSET_ROWSET屬性集,是一個只讀屬性再獲得結(jié)果集對象后,通過IRowsetInfo接口的GetProperties函數(shù)得到該
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 高中語文第6課語言的藝術(shù)第1節(jié)語不驚人死不休-選詞和煉句課件新人教版選修語言文字應用
- 概預算第六章公路工程定額
- 增城市英語短文語法填空閱讀理解高考一輪訓練及答案
- Windows Server網(wǎng)絡(luò)管理項目教程(Windows Server 2022)(微課版)10.4 拓展案例1 NAT服務(wù)器
- 江蘇省徐州市邳州市2023-2024學年九年級上學期期中抽測物理試卷(含答案解析)
- 小學五年級上冊安全教育教案 全冊
- 2024八年級英語上冊Unit8HowdoyoumakeabananamilkshakePeriod2SectionAGrammarFocus-3c習題課件新版人教新目標版
- 大學水土保持學006第三章土壤侵蝕原理土壤侵蝕規(guī)律
- 語法高中英語句子成分詳細解析教你如何分解英語句子
- 高中物理第二章恒定電流課時13串聯(lián)電路和并聯(lián)電路課件新人教版選修3-
- 《建筑構(gòu)造》概論復習題
- DB32T 4115-2021 鉆孔灌注樁成孔、地下連續(xù)墻成槽質(zhì)量檢測技術(shù)規(guī)程
- 部編版《aieiui》(完美版)課件
- 瓦斯抽采方法及鉆場孔布置課件
- DB11-T1811-2020廚房、廁浴間防水技術(shù)規(guī)程
- (新版)汽車底盤構(gòu)造與維修(全套319張課件)
- 我們都是少先隊員課件教學
- 《創(chuàng)新方法TRIZ理論入門》課件-第3章-功能分析
- 冷凍食品企業(yè)質(zhì)量管理手冊
- 平衡和協(xié)調(diào)能力的評定課件
- 殷長軍CTA指導下腹腔鏡腎部分切除術(shù)課件
評論
0/150
提交評論