SQLite3简单C++包装类源码示例
2014-10-10 17:43
555 查看
一个比较好的SQLite3 C++ wrapper包装类的通常思路是这样的:
数据库连接类,包含连接池,和sqlite3*,负责与数据库文件的连接问题;
一些create table,insert,update,delete等操作都在这里定义,直接使用sqlite3_exec()函数进行就可以,对它的回调函数可以定义为空。
如果对数据库执行查询操作,则需要一个单独的操作类, CQuery,它调用更具体的接口,先获取结果集,再逐行解析字段名和值,最后删除结果集
这里的重点是,首次将列字段名保存下来,再每次获取一行记录,将字段值记录到一个向量中,使用sqlite3_column_text()将每个字段统一存为一个字符串,在需要处理时再分别转换为具体的数据类型。
当进行下一行解析时,先要将原来的数据清除,在存放当前行的数据。注意存放的是const char*, 这和
这个例子我比较欣赏,准备在它的基础上编写一个简单的SQLite C++ wrapper类。参见下面的代码:
注意:
需要先安装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*,负责与数据库文件的连接问题;
一些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 object sqlite3_stmt* stmt; //prepared statement object size_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 directly sqlite3_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
相关文章推荐
- 简单C++线程池包装类源码示例
- C++调用SQLite简单示例
- c++ 文件读写简单示例
- ORM,ASP.NET中ORM学习,ASP.NET中ORM学习心得,WEB2.0中ORM实现原理,Asp.net简单ORM示例源码详细讲解,Asp.net2.0:如何使用ObjectDataSource(配合ORM )(二)
- 企业库、抽象工厂、单例、反射、分层的简单的学习示例源码【转】
- 用jna实现调用c++的dll简单示例
- C++中回调函数的简单示例
- 如何使用DOTMSN开发简单的MSN机器人示例(附示例源码)
- C++中enum的使用的一个简单示例
- C# 发送邮件【简单示例-源码】
- delegate的参数也可泛型【简单源码示例】
- 【android】sqlite+content provider+cursor adapter的最简单实现示例
- VC6.0配置LUA编译环境及LUA调用C++函数的简单示例
- Asp.net简单ORM示例源码详细讲解二
- Asp.net简单ORM示例源码详细讲解三
- dwr 源码 dwr的简单实现 dwr简单示例
- ORM,ASP.NET中ORM学习,ASP.NET中ORM学习心得,WEB2.0中ORM实现原理,Asp.net简单ORM示例源码详细讲解,Asp.net2.0:如何使用ObjectDataSource(配合ORM )
- WCF 简单示例程序(源码下载)
- MVC架构探究及其源码实现(6)-简单示例
- 一个简单的示例讲解游戏游戏编程原理。附示例源码