从上面的网址可以找到对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等等。因为我通常是在Windows CE嵌入式操作系统上开发APP,而Windows CE操作系统只支持Unicode字符集,所以今天要学习和测试的是Unicode版“C++ Wrappers”: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,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,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