一个比较好的SQLite3 C++ wrapper包装类的通常思路是这样的:
数据库连接类,包含连接池,和sqlite3*,负责与数据库文件的连接问题;
一些create table,insert,update,delete等操作都在这里定义,直接使用sqlite3_exec()函数进行就可以,对它的回调函数可以定义为空。
如果对数据库执行查询操作,则需要一个单独的操作类, CQuery,它调用更具体的接口,先获取结果集,再逐行解析字段名和值,最后删除结果集
这里的重点是,首次将列字段名保存下来,再每次获取一行记录,将字段值记录到一个向量中,使用sqlite3_column_text()将每个字段统一存为一个字符串,在需要处理时再分别转换为具体的数据类型。
当进行下一行解析时,先要将原来的数据清除,在存放当前行的数据。注意存放的是const char*, 这和
const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
定义是相符合的。
上面是两种完全不同的处理方法。
目前我通过实践,摸透了两个例子
https://github.com/wrmsr/SQLiteDB

这个例子我比较欣赏,准备在它的基础上编写一个简单的SQLite C++ wrapper类。参见下面的代码:

//
//#ifndef __SQLITE3_WRAPPER_H__
#define __SQLITE3_WRAPPER_H__#include <map>
#include <string>
#include <sstream>
#include <vector>
#include <memory>#include <stdlib.h>
#include <stdio.h>
#include <sqlite3.h>class CException: std::exception {public:CException(int _rc): rc(_rc) {stringstream ss;ss << rc;msg = ss.str();}CException(const char* _msg): msg(_msg) {}~CException() throw(){}int getCode() const { return rc; }const char* getMessage() const { return msg.c_str(); }protected:int rc;string msg;
};class CSQLite3;
class CQuery{public:CQuery(CSQLite3& _db, const char* sql);~CQuery();CSQLite3& getDB() const { return db; }size_t  getPos() const { return pos; }size_t getNumCols() const { return cols.size(); }//最核心的函数, 会被反复调用, 每次从结果集中读取出一行(ie.一条记录), 存放在vals向量中bool read_one_row();int getColIdx(const char* col) const;const char* getVal(size_t idx) const;const char* getVal(const char* col) const;const char* operator[](int idx) const;const char* operator[](const char* col) const;int getVals(map<string, string>& pair) const;private:CQuery(const CQuery& src);CSQLite3& db;  //database connection objectsqlite3_stmt* stmt; //prepared statement objectsize_t pos; //用于区分出列名而非记录vector<const char*> cols; //列名组成的向量vector<const char*> vals; //每次只保存一条记录(也就是一行)的数据, 下次处理时会首先清空再存放下一条记录map<string, int> colIdxs; //列名和索引对应的记录
};class CSQLite3{public:CSQLite3(const char* path, int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, const char* zVfs = NULL);~CSQLite3();sqlite3* getConn() const { return conn; }typedef int (*Callback)(void*, int, char**, char**);void exec(const char* sql, Callback cb = NULL, void* arg = NULL);string execStr(const char* sql);long long execInt(const char* sql);unsigned long long execUInt(const char* sql);std::auto_ptr<CQuery> execCQuery(const char* sql);int execOne(const char* sql, map<string, string>& pair);private:sqlite3* conn;
};#endif

下面是源文件

#include "sqlite3_wrapper.h"CQuery::CQuery(CSQLite3& _db, const char* sql): db(_db), stmt(NULL), pos(0) {int rc = sqlite3_prepare_v2(db.getConn(), sql, -1, &stmt, NULL);if(rc)throw CException(rc);
}CQuery::~CQuery(){if(stmt)sqlite3_finalize(stmt);
}//该函数会反复调用,每次只保存一行的值
bool CQuery::read_one_row() {int rc = sqlite3_step(stmt);if(rc != SQLITE_ROW && rc != SQLITE_DONE)throw CException(rc);//仅在开始获取列名向量, 以后直接跳过if(pos++ < 1) {size_t numCols = sqlite3_column_count(stmt);cols.reserve(numCols);vals.reserve(numCols);for(size_t i = 0; i < numCols; i++) {const char* col = sqlite3_column_name(stmt, i);cols.push_back(col);colIdxs[std::string(col)] = i;}}//如果没有下一条记录就返回, 这说明我们已经读完了if(rc == SQLITE_DONE)return false;//还有下一条记录可以读, 先清空存放该记录值的向量vals.clear();for(size_t i = 0; i < getNumCols(); i++) {const char* val = (const char*)sqlite3_column_text(stmt, i);vals.push_back(val);}return true;
}//找出列名在向量中对应的索引值
int CQuery::getColIdx(const char* col) const {std::map<std::string, int>::const_iterator i = colIdxs.find(std::string(col));if(i != colIdxs.end())return (*i).second;return -1;
}const char* CQuery::getVal(size_t idx) const {if(idx < 0 || idx > getNumCols())return NULL;return vals[idx];
}const char* CQuery::getVal(const char* col) const {return getVal(getColIdx(col));
}const char* CQuery::operator[](int idx) const {return getVal(idx);
}const char* CQuery::operator[](const char* col) const {return getVal(col);
}int CQuery::getVals(map<string, string>& pair) const {for(size_t i = 0; i < getNumCols(); i++)pair[std::string(cols[i])] = getVal(i);return 0;
}CSQLite3::CSQLite3(const char* path, int flags, const char* zVfs): conn(NULL) {int rc = sqlite3_open_v2(path, &conn, flags, zVfs);if(rc)throw CException(rc);
}CSQLite3::~CSQLite3(){if(conn)sqlite3_close(conn);
}void CSQLite3::exec(const char* sql, Callback cb, void* arg) {char* error = NULL;int rc = sqlite3_exec(conn, sql, cb, arg, &error);if(error) {CException ex(error);sqlite3_free(error);throw ex;}if(rc)throw CException(rc);
}string CSQLite3::execStr(const char* sql) {std::string ret;CQuery c(*this, sql);if(c.read_one_row() && c.getNumCols() > 0)ret = c[0];return ret;
}long long CSQLite3::execInt(const char* sql) {CQuery c(*this, sql);if(!c.read_one_row() || c.getNumCols() < 1)return -1;return strtoll(c[0], NULL, 10);
}unsigned long long CSQLite3::execUInt(const char* sql) {CQuery c(*this, sql);if(!c.read_one_row() || c.getNumCols() < 1)return -1;return strtoull(c[0], NULL, 10);
}std::auto_ptr<CQuery> CSQLite3::execCQuery(const char* sql) {return std::auto_ptr<CQuery>(new CQuery(*this, sql));
}//成功返回0, 失败返回1
int CSQLite3::execOne(const char* sql, map<string, string>& pair) {CQuery c(*this, sql);if(!c.read_one_row()) {return 1;}return c.getVals(pair);
}

下面是测试文件

//g++ -g test_sqlite3.cpp sqlite3_wrapper.cpp -o test_sqlite3 -lsqlite3
//
#include <iostream>
#include <unistd.h>#include "sqlite3_wrapper.h"int main() {try {unlink("test.db");CSQLite3 db("test.db");db.exec("create table test(id int primary key, value int);");for(int i = 0; i < 100; i++) {std::stringstream sql;sql << "insert into test values(" << i << ", " << i * 2 << ");";db.exec(sql.str().c_str());}std::cout << "Max: " << db.execInt("select max(value) from test;") << std::endl;CQuery query(db, "select * from test order by value desc;");while(query.read_one_row())std::cout << query["id"] << " = " << query["value"] << std::endl;//some arbitrary op to show that you can easily get the sqlite3 object and do whatever to it directlysqlite3_interrupt(db.getConn());}catch(CException ex) {std::cout << "SQLite exception: " << ex.getMessage() << std::endl;}return 0;
}

注意:

需要先安装sqlite3动态库,在Ubuntu 14.04 64bit上输入如下命令
sudo apt-get install sqlite3 libsqlite3-dev
在CentOS上面安装
yum -y install sqlite-devel
下面是运行截图
参考文献
[1].https://github.com/wrmsr/SQLiteDB

SQLite3简单C++包装类源码示例相关推荐

  1. 简单C++线程池包装类源码示例

    这里给出一个简单的C++线程池包装类,该类具有的特点是: 1.线程池大小是固定的, 一创建后,就不具有伸缩特性. 一般建议是 CPU核心数的2倍或1倍. 2.简单但是很可靠. 3.资源占用极低. 在开 ...

  2. hmac-sha1加密算法C源码示例

    HMAC: Hash-based Message Authentication Code,即基于Hash的消息鉴别码 在各大开放平台大行其道的互联网开发潮流中,调用各平台的API接口过程中,无一例外都 ...

  3. WinFormreportViewer(rdlc)报表[列表]的使用(一)(附源码示例) 之配餐系统的开发

    紧接着"WinForm"reportViewer报表[矩阵]的使用(一)(附源码示例)" 之配餐系统的开发"这篇文章,此文与大家分享的是在 配餐系统的开发 中使 ...

  4. WinFormreportViewer报表[矩阵]的使用(一)(附源码示例) 之配餐系统的开发

    winform开发中,报表在大多管理软件和数据分析中是必备的一个功能,追求简单.快捷.美观的报表开发是大家在做此类应用时比较关心的问题.就winform中的报表控件:大家熟知.不错的有reportVi ...

  5. Linux Zero-copy零拷贝技术:源码示例

    <Linux Zero-copy零拷贝技术:源码示例> <Linux Zero-copy零拷贝技术全面揭秘> <什么是mmap?零拷贝?DMA?> <Linu ...

  6. 【2021软件创新实验室暑假集训】SpringMVC框架(设计原理、简单使用、源码探究)

    系列文章目录 20级 Java篇 [2021软件创新实验室暑假集训]计算机的起源与大致原理 [2021软件创新实验室暑假集训]Java基础(一) [2021软件创新实验室暑假集训]Java基础(二) ...

  7. 视觉机器学习20讲-MATLAB源码示例(6)-贝叶斯学习算法

    视觉机器学习20讲-MATLAB源码示例(6)-贝叶斯学习算法 1. 贝叶斯学习算法 2. Matlab仿真 3. 小结 1. 贝叶斯学习算法 贝叶斯分类算法是统计学的一种分类方法,它是一类利用概率统 ...

  8. 视觉机器学习20讲-MATLAB源码示例(3)-回归学习算法

    视觉机器学习20讲-MATLAB源码示例(3)-回归学习算法 1. 回归学习算法 2. Matlab仿真 3. 仿真结果 4. 小结 1. 回归学习算法 回归学习(Regression Learnin ...

  9. 视觉机器学习20讲-MATLAB源码示例(2)-KNN学习算法

    视觉机器学习20讲-MATLAB源码示例(2)-KNN学习算法 1. KNN学习算法 2. Matlab仿真 3. 仿真结果 4. 小结 1. KNN学习算法 KNN(K-Nearest Neighb ...

最新文章

  1. python heap_python topN max heap,使用heapq还是自己实现?
  2. 如何设计一个良好的接口?
  3. linux 文件打开数设置, too ma
  4. 大数据下的BI新特性
  5. Python爬取小说
  6. pythons实现信号分帧
  7. 求有向图中两点最短距离java_Java 迪杰斯特拉算法实现查找最短距离
  8. Hexo博客搭建图文教程
  9. 如何导出ane所需的swc
  10. Project项目视图
  11. 2048小游戏微信小程序源码
  12. 商业计划汇报PPT模板
  13. 应急管理大屏可视化决策系统产品白皮书
  14. MongoDB3:复制集
  15. C++编程题最常用函数汇总
  16. 详解CSRF跨站点请求伪造
  17. Verilog硬件描述语言
  18. 软件开发常用词汇中英文对照
  19. Vis-MVSNet: Visibility-Aware Multi-view Stereo Network(IJCV 2022)
  20. 【SEUSE】编译原理 - 词法分析器

热门文章

  1. 面试题:查询连续出现的数字
  2. jquery checkbox勾选/取消勾选的诡异问题
  3. OC中的NSArray和NSMutableArray、NSDictionary和NSMutableDictionary用法
  4. mysql操作数字名称的schema时字符的逃逸问题
  5. 跨域部署Silverlight时需要注意的问题
  6. ORB_SLAM2源码:ORBmatcher.cc
  7. usaco Postal Vans(dp)
  8. 运行php能运行asp么,配置使web server即能运行asp又能运行PHP(不装Apache)
  9. linux互斥锁和条件变量,如何理解互斥锁和条件变量?
  10. php path当局者迷,当局者迷_成语故事_有品有墨_品故事 写人生