SQLite3資料庫Native C++封裝類(Unicode)CppSQLite3U的初步認識與使用
SQLite3資料庫Native C++封裝類(Unicode)CppSQLite3U的初步認識與使用 by斜風細雨QQ:253786989 2012-02-12
(1)
從上面的網址可以找到對SQLite資料庫的C API的各種語言的封裝。包括c、c++、vb、c#.net、delphi、Lisp、D、Java、Javascript、Objective-C、Perl、PHP、Python、Ruby、Lua、Fortran等等。從這也可以看出SQLite資料庫作為本地資料儲存工具而得到的廣泛應用。單單是“C++
Wrappers”也有幾十種,常見的如:easySQLite、SQLite++、CppSQLite、CppSQLiteU
(2)
因為是在Windows CE作業系統上使用SQLite,所以在使用CppSQLiteU之前,要先編譯針對Windows CE平臺的SQLite3 DLL。這一步省了,我直接借用了別人已經編譯好的。
(3)
下面是一個簡單測試示例,主要是利用class CppSQLite3DB新建資料庫、建立表、插入刪除更新記錄、使用事務、查詢記錄等等。
#define SQLITE3_FILE_NAME TEXT("sqlite.db3") // 獲取程式當前路徑 void GetCurrentDirectory(CString &szPath) { TCHAR buf[256] = {0}; GetModuleFileName(NULL, buf, sizeof(buf)/sizeof(TCHAR)); szPath = buf; szPath = szPath.Left(szPath.ReverseFind('\\') + 1); } CString strDbPath; GetCurrentDirectory(strDbPath); strDbPath += SQLITE3_FILE_NAME; CppSQLite3DB db; try { // 開啟或新建一個數據庫 db.open(strDbPath); // 判斷表名是否已經存在 if(!db.tableExists(TEXT("Customers"))) { // 不存在,新建表Customers db.execDML(TEXT("CREATE TABLE Customers(cust_name varchar(50) NOT NULL PRIMARY KEY, cust_address varchar(50));")); } // 插入1條記錄 db.execDML(TEXT("INSERT INTO Customers VALUES('Village Toys', '200 Maple Lane');")); // 插入1條記錄 db.execDML(TEXT("INSERT INTO Customers VALUES('Kids Place', '333 South Lake Drive');")); // 刪除1條記錄 db.execDML(TEXT("DELETE FROM Customers WHERE cust_name = 'Village Toys';")); // 使用顯示事務插入10條記錄 TCHAR buf[256] = {0}; db.execDML(TEXT("BEGIN TRANSACTION;")); for (int i = 0; i < 10; ++i) { memset(buf, 0, sizeof(buf)); wsprintf(buf, TEXT("INSERT INTO Customers VALUES ('Fun%dALL', '%d Sunny Place');"), i, i); db.execDML(buf); } db.execDML(TEXT("COMMIT TRANSACTION;")); // 更新1條記錄 db.execDML(TEXT("UPDATE Customers SET cust_address = '4545 53rd Street' WHERE cust_name = 'Fun0ALL';")); // 獲取總記錄條數 int nCount = db.execScalar(TEXT("SELECT COUNT(*) FROM Customers;")); TCHAR szCount[50] = {0}; memset(szCount, 0, sizeof(szCount)); wsprintf(szCount, TEXT("Record count: %d."), nCount); AfxMessageBox(szCount); // 獲取每一條記錄 CppSQLite3Query q = db.execQuery(TEXT("SELECT * FROM Customers;")); while (!q.eof()) { AfxMessageBox(q.fieldValue(0)); q.nextRow(); } // 銷燬語句 q.finalize(); // 關閉資料庫 db.close(); AfxMessageBox(TEXT("測試完成!")); } catch(CppSQLite3Exception ex) { AfxMessageBox(ex.errorMessage()); }
(4)
CppSQLite3U封裝了4個類:CppSQLite3Exception、CppSQLite3DB、CppSQLite3Statement、CppSQLite3Query。
a) CppSQLite3Exception用於捕捉異常,errorCode以整數類形返回錯誤碼,errorMessage以Unicode字串型別返回錯誤碼。
class CppSQLite3Exception { public: … … const int errorCode() { return mnErrCode; } LPCTSTR errorMessage() { return mpszErrMess; } static LPCTSTR errorCodeAsString(int nErrCode); … … };
通常用法如:
try
{
… …
}
catch(CppSQLite3Exception ex)
{
AfxMessageBox(ex.errorMessage());
}
b) CppSQLite3DB用於新建資料庫,開啟關閉資料庫連線,執行DML、DDL,檢索資料等。如:open開啟資料庫連線,close關閉資料庫連線,tableExists檢查某表是否存在,execDML執行SQL命令,execQuery檢索記錄,setBusyTimeout設定SQLite內部的busy handler的超時時間,SQLiteVersion返回SQLite版本。
class CppSQLite3DB
{
public:
… …
void open(LPCTSTR szFile);
void close();
bool tableExists(LPCTSTR szTable);
int execDML(LPCTSTR szSQL);
CppSQLite3Query execQuery(LPCTSTR szSQL);
int execScalar(LPCTSTR szSQL);
CString execScalarStr(LPCTSTR szSQL);
CppSQLite3Statement compileStatement(LPCTSTR szSQL);
sqlite_int64 lastRowId();
void interrupt() { sqlite3_interrupt(mpDB); }
void setBusyTimeout(int nMillisecs);
static const char* SQLiteVersion() { return SQLITE_VERSION; }
… …
};
c) CppSQLite3Statement也可以執行SQL命令,它最大的特點是支援引數繫結。對於引數繫結的用處,參考“SQlite資料庫的C程式設計介面(四) 繫結引數(Bound Parameters) ——《Using SQlite》讀書筆記”學習。該類匯出的介面函式中,bind用於給SQL語句中的引數繫結指定的值,reset函式用於重置SQL語句,finalize用於銷燬語句。
class CppSQLite3Statement
{
public:
… …
CppSQLite3Statement& operator=(const CppSQLite3Statement& rStatement);
int execDML();
CppSQLite3Query execQuery();
void bind(int nParam, LPCTSTR szValue);
void bind(int nParam, const int nValue);
void bind(int nParam, const double dwValue);
void bind(int nParam, const unsigned char* blobValue, int nLen);
void bindNull(int nParam);
void reset();
void finalize();
… …
};
用法如:
try
{
CppSQLite3DB db;
db.execDML("CREATE TABLE emp(empno int, empname char(20));");
db.execDML("BEGIN TRANSACTION;");
CppSQLite3Statement stmt = db.compileStatement("INSERT INTO emp VALUES (:empno, : empname);");
for (i = 0; i < nRowsToCreate; ++i)
{
char buf[16];
sprintf(buf, "EmpName%06d", i);
stmt.bind(":empno", i);
stmt.bind(":empname ", buf);
stmt.execDML();
stmt.reset();
}
db.execDML("COMMIT TRANSACTION; ");
}
catch (CppSQLite3Exception& e)
{
cerr << e.errorCode() << ":" << e.errorMessage() << endl;
}
d) CppSQLite3Query用於檢索記錄並讀出結果。它匯出的public介面函式大多都是SQLite3的C API _sqlite3_column_xxx函式的封裝,通過該API函式讀取結果集中某一行的某一列。nextRow函式用於檢索下一行,eof用於判斷是否到結果集的結尾。
class CppSQLite3Query
{
public:
… ….
int numFields();
int fieldIndex(LPCTSTR szField);
LPCTSTR fieldName(int nCol);
LPCTSTR fieldDeclType(int nCol);
int fieldDataType(int nCol);
LPCTSTR fieldValue(int nField);
LPCTSTR fieldValue(LPCTSTR szField);
int getIntField(int nField, int nNullValue=0);
int getIntField(LPCTSTR szField, int nNullValue=0);
double getFloatField(int nField, double fNullValue=0.0);
double getFloatField(LPCTSTR szField, double fNullValue=0.0);
LPCTSTR getStringField(int nField, LPCTSTR szNullValue=_T(""));
LPCTSTR getStringField(LPCTSTR szField, LPCTSTR szNullValue=_T(""));
const unsigned char* getBlobField(int nField, int& nLen);
const unsigned char* getBlobField(LPCTSTR szField, int& nLen);
bool fieldIsNull(int nField);
bool fieldIsNull(LPCTSTR szField);
bool eof();
void nextRow();
void finalize();
… …
};
SQLite3資料庫Native C++封裝類(Unicode)CppSQLite3U的初步認識與使用 by斜風細雨QQ:253786989 2012-02-12