8.1 數據庫的基本介紹php
數據庫是以必定組織方式儲存在一塊兒的,能爲多個用戶共享的,具備儘量小的冗餘度的、與應用彼此獨立的相互關聯的數據集合,數據庫是存儲數據的重要方式,已經應用到多種不一樣的場合。Windows CE系統支持兩種類型的數據庫:內嵌的CE數據庫(CEDB)和嵌入式數據庫EDB。其中CEDB是較老的數據庫引擎,已沒法知足如今如此大量和複雜要求的數據處理,不過爲了向下兼容,仍是保留在Windows CE系統中。CEDB是從Windows CE5.0開始引入的一個新的高效的數據庫引擎,可以支持事務以及更大數據量的流式訪問。數據庫
在Windows CE中,數據庫被組織在數據庫卷中,首先須要將數據庫掛載到系統的某個目錄下,才能訪問。一個數據庫卷能夠包含多個不一樣類型的數據庫,每一個數據庫包含多條記錄,每一個記錄能夠包含多個屬性,實際上能夠看做一張表,每行表明一個記錄,每列表明記錄內的一個屬性。每一個屬性能夠指定爲不一樣的數據類型,在EDB中能夠支持13種數據類型,其中包含9個CEDB也支持以及4個只有EDB才能支持的類型,表8-1列出了EDB中支持的數據類型。緩存
表8-1 EDB支持的數據類型數據結構
數據類型ide |
說明函數 |
CEVT_BLOB性能 |
CEBLOB結構,表明字節集合大數據 |
CEVT_BOOLui |
布爾類型spa |
CEVT_FILETIME |
日期時間結構 |
CEVT_I2 |
16位有符號整數 |
CEVT_I4 |
32位有符號整數 |
CEVT_LPWSTR |
以null結尾的Unicode字符串 |
CEVT_R8 |
64位的浮點實數 |
CEVT_UI2 |
16位無符號整數 |
CEVT_UI4 |
32位無符號整數 |
CEVT_STREAM |
只有EDB支持,一個大的二進制數據流 |
CEVT_RECID |
只有EDB支持,一個128位的表明記錄標識的GUID |
CEVT_AUTO_I4 |
只有EDB支持,自動生成的32位有符號整數 |
CEVT_AUTO_I8 |
只有EDB支持,自動生成的64位有符號整數 |
其中CEVT_STREAM數據類型對於訪問大的數據對象十分有用,好比圖片,e-mail中的附件,因爲流式訪問的數據是單獨存儲在數據庫中的數據頁面上,而不是放在數據庫的某一行中,流式訪問比較高效。EDB中限制每一個記錄最大爲8KB,而流對象不受單個記錄大小的限制,流對象最大能夠爲32MB,後面將介紹如何使用流對象來讀寫記錄的數據。
下面咱們重點介紹EDB數據庫開發的API。
8.2 EDB數據庫開發API
8.2.1 掛載及卸載數據庫卷
若是數據庫卷以文件的形式存放在某個外部存儲設備上,那麼在打開數據庫以前須要先掛載數據庫卷,在關閉數據庫後,須要卸載數據庫卷。Win 32 API提供的CeMountDBVolEx()函數用於掛載數據庫卷,它既可建立一個新的卷,也能夠打開一個已經存在的卷:
BOOL CeMountDBVolEx(
PCEGUID pGuid,
LPWSTR lpwszDBVol,
CEVOLUMEOPTIONS* pOptions,
DWORD dwFlags
);
l 參數pGuid爲一個輸出參數,指向一個CEGUID數據類型的指針,用於返回掛載數據庫卷的全局標識符,CEGUID用於追蹤已打開數據庫卷的句柄。、
l 參數lpszDBVol指定將被掛載的數據庫卷所在的文件名,一個數據庫卷能夠包含多個數據庫。
l 參數pOptions爲一個指向結構體CEVOLUMEOPTIONS的指針,用於在數據庫卷被第一次掛載時設置數據庫卷的管理方式。參數pOptions能夠設置爲NULL,將使用系統的默認管理方式。結構體CEVOLUMEOPTIONS的定義如下:
typedef struct CEVOLUMEOPTIONS {
WORD wVersion;
DWORD cbBufferPool;
DWORD dwAutoShrinkPercent;
DWORD dwFlushInterval;
DWORD cMaxNotifyChanges;
DWORD dwDefaultTimeout;
WCHAR wszPassword[CCH_MAX_PASSWORD + 1];
DWORD dwFlags;
} CEVOLUMEOPTIONS;
n 成員wVersion表明結構體的版本,必須設置爲1。
n 成員cbBufferPool表明所用緩衝池的字節數。
n 成員dwAutoShrinkPercent表明自動收縮百分比,當數據庫卷內的可用空間低於這個值時,操做系統會觸發自動收縮線程,回收可用空間。
n 成員dwFlushInterval表明數據庫引擎的自動回寫時間間隔,單位爲秒。
n 成員cMaxNotifyChanges表明對於一個事務能夠緩存在隊列中的最大更改數量。
n 成員dwDefaultTimeout表明超時時間,單位爲毫秒。
n 成員wszPassword表明數據庫卷的密碼。
n 成員dwFlags表明結構體中包含有效值的成員,其它的成員將使用系統默認值。
l 參數dwFlags指定掛載數據庫卷的方式,可取值如表8-1所列:
表8-1 掛載數據庫卷的可取方式
可取值 |
說明 |
CREATE_ALWAYS |
老是建立新的數據庫卷,若是指定名字的數據庫卷已經存在,則將其覆蓋 |
CREATE_NEW |
新建一個數據庫卷,若是指定名字的數據庫卷已經存在,則函數調用將失敗 |
OPEN_ALWAYS |
老是打開數據庫卷,若是指定名字的數據庫卷不存在,就先新建立一個 |
OPEN_EXISTING |
打開數據庫卷,若是不存在,則函數調用將失敗 |
TRUNCATE_EXISTING |
打開數據庫卷,並刪除數據庫捲上的所有數據,包括全部數據庫和記錄。若是指定名字的數據庫卷不存在,函數調用將失敗 |
若是掛載數據庫捲成功,函數將返回TRUE,參數pceguid將返回掛載數據庫卷的CEGUID,這個將被用於多個數據庫操做的函數中;返回FALSE表示掛載失敗,調用GetLastError()函數進一步獲取錯誤信息,可取的錯誤信息以下:
l ERROR_ALREADY_EXISTS: 函數調用成功,並且數據庫在函數調用以前已經存在,此時參數dwFlags被設置爲OPEN_ALWAYS或CREATE_ALWAYS。
l ERROR_ACCESS_DENIED: 表明以下錯誤,參數dwFlags被設置爲TRUNCATE_EXISTING並且數據庫卷已經被掛載或文件不容許被截短,或者數據庫卷爲只讀。
l ERROR_BAD_FORMAT: 數據庫卷被指定爲其它版本的EDB。
l ERROR_FILE_NOT_FOUND: 指定爲TRUNCATE_EXISTING可是卷不存在。
l ERROR_INVALID_PARAMETER: 指定了錯誤的參數,如將參數pGuid設置爲NULL。
l ERROR_WRONG_PASSWPRD: 錯誤的數據庫卷密碼。
注意,在Windows CE中,容許一個數據庫卷被屢次掛載,每被掛載一次,數據庫卷的引用計數就會自動加1,而調用CeUnmountDBVol()函數實際上將引用計數減1,直到應用計數減爲0,數據庫卷才被從系統中卸載。若是一個數據庫卷已經被掛載,則不容許新建立該名字的數據庫卷或將數據庫卷清空,將返回ERROR_ACCESS_DENIED錯誤。
使用完數據庫卷以後,必定要記得將其卸載,這樣才能釋放資源,卸載數據庫卷調用函數CeUnmountDBVol()實現:
BOOL CeUnmountDBVol(
PCEGUID pGuid
);
l 參數pGuid指定須要卸載的數據庫卷的CEGUID,就是咱們前面掛載數據庫卷返回的全局標識。
若是卸載數據庫捲成功,函數返回TRUE,並且全部緩存的對數據庫卷的更新將永久寫回到存儲設備中。掛載失敗將返回FALSE。一旦將數據庫卷掛載,標識CEGUID將無效,不能再使用。
8.2.2 枚舉數據庫卷
應用程序能夠枚舉系統中當前正被掛載的全部數據庫卷的CEGUID和名字,函數CeEnumDBVolumes()實現枚舉功能:
BOOL CeEnumDBVolumes(
PCEGUID pGuid,
LPWSTR pwszName,
DWORD cchMaxName
);
l 參數pGuid爲輸入輸出參數,返回下一個數據庫卷的CEGUID。
l 參數pwszName爲輸出參數,用於返回下一個數據庫卷的名字,爲一個指向內存緩衝區的指針。
l 參數cchMaxName指定上面緩衝區的大小,單位爲字節,至少應該設置爲CEDB_MAXDBASENAMELEN,
函數調用成功將返回TRUE,失敗將返回FALSE。若是須要查詢具體的錯誤信息,可進一步調用GetLastError()函數,可能的值有:
l ERROR_INSUFFICIENT_BUFFER: 指定的緩衝區空間不夠。
l ERROR_INVALID_PARAMETER: 其中的某個參數非法,參數pGuid或pwszName被設置爲NULL。
l ERROR_NO_MORE_ITEMS: 沒有新的掛載數據庫卷,這個將被用於判斷枚舉是否結束。
l ERROR_KEY_DELETED: 枚舉掛載數據庫卷只能從一個非法的GUID或一個已經掛載的捲開始。其它的GUID都將失敗,好比使用一個已經被刪除的卷的GUID。
這個函數的使用方式比較特殊,爲了獲得系統中第一個已掛載的數據庫卷信息,第一次調用該函數須要經過CREATE_INVALIDGUID宏將參數pceguid設定爲無效值。函數調用成功後,pceguid將返回數據庫卷對應的CEGUID。爲了枚舉下一個數據庫卷的信息,須要將上次調用返回的pceguid參數傳入,再次調用該函數便可。這樣循環調用直到返回FALSE爲止,就能枚舉掛載的全部數據庫卷。下面的代碼演示枚舉過程:
CEGUID ceguid;
TCHAR szVolume[CEDB_MAXDBASENAMELEN];
CREATE_INVALIDGUID(&ceguid);
While(CeEnumDBVolumes(&ceguid, szVolume, sizeof(szVolume)))
{
//輸出掛載的數據庫卷信息
}
8.2.3 枚舉數據庫
若是但願進一步查看每一個掛載的數據庫卷內包含的數據庫信息,能夠經過EDB提供另外兩個的API函數實現:CeFindFirstDatabaseEx()函數返回數據庫卷內的第一個數據庫的查找句柄,而後使用這個查找句柄調用CeFindNextDatabaseEx()繼續查找數據庫。
CeFindFirstDatabaseEx()函數的原型以下:
HANDLE CeFindFirstDatabaseEx(
PCEGUID pGuid,
DWORD dwDbaseType
);
l 參數pGuid指定數據庫卷的CEGUID。這個參數能夠設置爲NULL或由CREATE_INVALIDEDBGUID宏產生,就表示將對全部的掛載數據庫捲進行枚舉;不然只枚舉指定的數據庫卷。
l 參數dwDbaseType指定枚舉數據庫的類型。若是這個值設置爲0,將枚舉數據庫卷內全部類型的數據庫,不然只枚舉指定類型的數據庫。
函數調用成功,將返回一個用於枚舉數據庫上下文的查找句柄;失敗將返回INVALID_HANDLE_VALUE。
CeFindNextDatabaseEx()函數返回知足枚舉類型的數據庫的對象ID,函數原型爲:
CEOID CeFindNextDatabaseEx(
HANDLE hEnum,
PCEGUID pGuid
);
l 參數hEnum爲數據庫的查找句柄。
l 參數pGuid爲輸出參數,若是枚舉數據庫成功,返回下一個數據庫的GUID。若是不須要,能夠將這個參數設置爲NULL。
函數調用成功,返回下一個數據庫的對象ID;失敗則返回0。若是沒有其它的數據庫能夠枚舉,函數將返回0。枚舉數據庫的方法爲,不斷調用CeFindNextDatabaseEx()函數,直到函數返回0爲止,下面的代碼演示如何枚舉一個數據庫卷內全部數據庫:
HANDLE hDBList;
CEOID oidDB;
hDBList = CeFindFirstDatabaseEx (&ceguid,0);
if (hDBList != INVALID_HANDLE_VALUE)
{
oidDB = CeFindNextDatabaseEx (hDBList,&ceguid);
//判斷是否達到枚舉最後
while (oidDB)
{
//對數據庫進行操做
//繼續往下枚舉數據庫
oidDB = CeFindNextDatabaseEx (hDBList,&ceguid);
}
//枚舉數據庫完畢,關閉數據庫查找句柄
CloseHandle (hDBList);
8.2.4 查詢對象信息
在Windows CE中,數據庫和記錄都被看做是一個對象,數據庫的信息經過查詢對象信息的函數CeOidGetInfoEx2()獲取:
BOOL CeOidGetInfoEx2(
PCEGUID pGuid,
CEOID oid,
CEOIDINFO* poidInfo
);
l 參數pGuid指定包含數據庫對象的掛載數據庫卷的CEGUID。
l 參數oid指定查詢的數據庫對象ID。
l 參數poidInfo爲輸入輸出參數,這是一個指向結構體CEOIDINFOEX的指針,用於接收返回的數據庫對象信息。結構體CEOIDINFOEX的定義以下:
typedef struct CEOIDINFOEX {
WORD wVersion;
WORD wObjType;
union {
CEFILEINFO infFile;
CEDIRINFO infDirectory;
CEDBASEINFO infDatabase;
CERECORDINFO infRecord;
};
} CEOIDINFOEX;
n 成員wVersion爲這個結構體的版本號,在Windows CE7中必須設置爲2。
n 成員wObjType指定對象的類型,可取值爲:OBJTYPE_DATABASE表明數據庫對象,OBJTYPE_RECORD表明記錄對象。
n 第3個成員由4個不一樣的結構體組成的一個聯合體,每一個結構體分別表示一種不一樣類型的對象信息,其中CEFILEINFO表明文件對象,CEDIRINFO表明目錄對象,CEDBASEINFO表明數據庫對象,CERECORDINFO表明數據庫內的一個記錄對象。這裏咱們只介紹數據庫對象和記錄對象,結構體CEDBASEINFO實際上就是結構體CEDBASEINFOEX,它的定義以下:
typedef struct CEDBASEINFOEX {
WORD wVersion;
WORD wNumSortOrder;
DWORD dwFlags;
WCHAR szDbaseName[CEDB_MAXDBASENAMELEN];
DWORD dwDbaseType;
DWORD dwNumRecords;
DWORD dwSize;
FILETIME ftLastModified;
SORTORDERSPECEX rgSortSpecs[CEDB_MAXSORTORDER];
} CEDBASEINFOEX;
n 成員wVersion表明該結構體的版本,必須設置爲2。
n 成員wNumSortOrder表明數據庫中活動排序字段的個數,在Windows CE7,一次最大能夠有32個活動的排序字段。
n 成員dwFlags表明該結構體後面的有效成員,可取值爲下面的一個或多個的組合:CEDB_VALIDDBFLAGS,CEDB_VALIDNAME,CEDB_NOCOMPRESS,CEDB_VALIDSORTSPEC, CEDB_VALIDTYPE。默認數據庫都是壓縮的,若是使用CEDB_NOCOMPRESS標誌,那麼新建立的數據庫將不會進行壓縮,這樣數據庫佔用的空間比較大可是讀寫速度會更快。
n 成員szDbaseName表明新建數據庫的名字,最大長度能夠爲CEDB_MAXDBASENAMELEN,新建數據庫時必須指定數據庫的名字。
n 成員dwDbaseType表明數據庫類型標識。
n 成員dwNumRecords表明數據庫的記錄個數。
n 成員dwSize和ftLastModified在EDB中沒用,爲了兼容CEDB版本的結構體。
n 成員rgSortSpecs表明排序字段定義。
結構體CERECORDINFO的定義以下:
typedef struct _CERECORDINFO
{
CEOID oidParent;
} CERECORDINFO;
惟一的成員oidParent表明記錄所在的數據庫的對象ID (OID)。
獲取對象信息成功,函數返回TRUE,失敗返回FALSE。
CeOidGetInfoEx2()函數能夠返回不少關於對象的有用信息,對於數據庫,經過OID能夠查詢數據庫的名稱,類型,包含的記錄個數等信息。
下面的代碼演示如何獲取指定數據庫包含的記錄個數:
CEOIDINFO dbinfo;
int recordsNum;
dbinfo. wVersion = 2;
dbinfo. wObjType = OBJTYPE_DATABASE;
CeOidGetInfoEx2(&ceguid, oidDB, &dbinfo);
recordsNum = dbinfo. infDatabase. dwNumRecords; //獲取數據庫的記錄個數
下面演示如何枚舉當前系統中掛載的全部數據庫卷以及每一個數據庫卷中包含的數據庫,這個程序的運行結果如圖8.1所示。上方的按鈕用於開始枚舉數據庫信息,結果將顯示在下面的列表框中。
圖8.1 枚舉數據庫的運行結果
對話框類的頭文件爲:
// EnumDataBaseEDBDlg.h : header file
//
#pragma once
#include "afxwin.h"
// CEnumDataBaseEDBDlg dialog
class CEnumDataBaseEDBDlg : public CDialog
{
// Construction
public:
CEnumDataBaseEDBDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
enum { IDD = IDD_ENUMDATABASEEDB_DIALOG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Implementation
protected:
HICON m_hIcon;
// Generated message map functions
virtual BOOL OnInitDialog();
#if defined(_DEVICE_RESOLUTION_AWARE) && !defined(WIN32_PLATFORM_WFSP)
afx_msg void OnSize(UINT /*nType*/, int /*cx*/, int /*cy*/);
#endif
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnBnClickedButtonEnumdb();
//CEdit m_EditDataBases;
CListBox m_ListDataBases;
};
下方按鈕的單擊事件處理函數爲:
void CEnumDataBaseEDBDlg::OnBnClickedButtonEnumdb()
{
// TODO: Add your control notification handler code here
CEGUID ceguid;
TCHAR szVolume[CEDB_MAXDBASENAMELEN];
m_ListDataBases.ResetContent();
CString outDBs = _T("Enum mounted volumes and databases:");
m_ListDataBases.AddString(outDBs);
CREATE_INVALIDGUID(&ceguid);
while(CeEnumDBVolumes(&ceguid, szVolume, sizeof(szVolume)))
{
//輸出掛載的數據庫卷名稱信息
outDBs.Format(_T(" %s:"),szVolume);
m_ListDataBases.AddString(outDBs);
//outDBs.Format(_T("%s\t\t%32s%20s%16s\r\n"),outDBs,_T("DBName"),_T("RecordNum"),_T("DBType"));
//枚舉每一個掛載卷下的數據庫:
HANDLE hDBList;
CEOID oidDB;
//打開數據庫查找句柄
hDBList = CeFindFirstDatabaseEx (
&ceguid,
0); //枚舉全部類型的數據庫
//獲得合法的數據庫查詢句柄
if (hDBList != INVALID_HANDLE_VALUE)
{
oidDB = CeFindNextDatabaseEx (hDBList,&ceguid);
//判斷是否達到枚舉最後
while (oidDB)
{
//對數據庫進行操做
CEOIDINFOEX dbinfo;
int recordsNum;
dbinfo.wVersion = 2;
dbinfo.wObjType = OBJTYPE_DATABASE;
//查詢數據庫對象信息
CeOidGetInfoEx2(&ceguid, oidDB, &dbinfo);
//獲取數據庫的記錄個數
recordsNum = dbinfo.infDatabase.dwNumRecords;
//分別輸出數據庫的名稱,記錄個數,以及數據庫類型
outDBs.Format(_T(" %32s%20d%16d"),dbinfo.infDatabase.szDbaseName,recordsNum, dbinfo.infDatabase.dwDbaseType);
m_ListDataBases.AddString(outDBs);
//繼續往下枚舉數據庫
oidDB = CeFindNextDatabaseEx (hDBList,&ceguid);
}
//枚舉數據庫完畢,關閉數據庫查找句柄
CloseHandle (hDBList);
}
else
{
//獲取出錯緣由
if (GetLastError () == ERROR_OUTOFMEMORY)
{
AfxMessageBox(_T("Failed Open DB enum handle: Out of memory"));
}
else
{
AfxMessageBox(_T("Failed Open DB enum handle: Unknown error"));
}
}
//從新初始化掛載卷名稱緩衝區
ZeroMemory(szVolume,CEDB_MAXDBASENAMELEN * 2);
}
//m_EditDataBases.SetWindowTextW(outDBs);
}
8.2.5 回寫數據庫卷
在Windows CE系統中,對掛載數據庫卷的更新操做都被緩存在內存中,爲了將更新強制回寫到永久存儲設備上,若是在回寫以前,系統重啓或斷電,那麼對數據庫卷的更新將丟失。函數CeFlushDBVol()強制回寫數據庫卷:
BOOL CeFlushDBVol(
PCEGUID pGuid
);
l 參數pGuid爲掛載的數據庫卷的全局標誌CEGUID。這個參數能夠設置爲NULL,此時將掛載的全部數據庫卷都回寫。
回寫成功,函數將返回TRUE,不然返回FALSE表明回寫失敗,進一步調用GetLastError()函數獲取出錯信息,可能的取值爲:
n ERROR_NOT_FOUND: 指定的pGuid表明的卷當前沒有被掛載。
n ERROR_INVALID_PARAMETER: 若是參數pGuid不爲NULL,可是指向一個非法的EDB卷,好比指向一個掛載的CEDB卷。
n ERROR_DISK_FULL: 數據庫卷所在的磁盤空間不足,沒法進行回寫操做。
實際上,當對數據庫卷的更新達到足夠的量,數據庫引擎會按期自動執行回寫。爲了保證更新的數據被順利回寫,須要應用調用這個函數。可是過於頻繁的調用回寫,將直接影響數據庫的性能,須要在兩者之間平衡。