使用C++模板封装SQLite(完整版)

    SQLite 是一款开源的嵌入式数据库,由于本身小巧玲珑,比较适合作为应用软件的一部分嵌入到程序中,SQLite提供了一套简单易用的C API供应用程序调用,  但由于API的使用比较繁杂,并且考虑到将来移植到不同数据库的需求,应当避免直接使用SQLite API,应对其适当的封装,增加代码的灵活性。本文就项目中的使用经验提供了一种封装的方法。

    1.API层的封装

    由于SQLite支持ansi && unicode,为同时支持char, wchar_t,一些API同时提供了两个版本,如sqlite3_open,sqlite3_open16,另外一些API则只有一个版本,基于这两点实现了两个简单的类别:SQLite_APIBase和SQLite_APITraits,,SQLite_APIBase包含char, wchar_t无关的API,SQLite_APITraits模板从SQLite_APIBase派生,并针对char, wchar_t提供了两个特化版本。如下:

 

 

  1. struct SQLite_APIBase 
  2. {
  3.     static int Close(sqlite3* pDb)
  4.     {
  5.         return sqlite3_close(pDb);
  6.     }
  7.     static int Prepare(sqlite3* db, wchar_t const* pszSQL, int nBytes, sqlite3_stmt **ppStmt, const void** pzTail)
  8.     {
  9.           return sqlite3_prepare16(db, pszSQL, nBytes, ppStmt, pzTail);
  10.     }
  11.     static int Step(sqlite3_stmt* pStmt)
  12.     {
  13.         return sqlite3_step(pStmt);
  14.     }
  15.     static int Finalize(sqlite3_stmt *pStmt)
  16.     {
  17.         return sqlite3_finalize(pStmt);
  18.     }
  19.     //set operations
  20.     static int BindInt(sqlite3_stmt *pStmt, int iIndex, int iValue)
  21.     {
  22.         return sqlite3_bind_int(pStmt, iIndex, iValue);
  23.     }
  24.     static int BindDouble(sqlite3_stmt *pStmt, int iIndex, double fValue)
  25.     {
  26.         return sqlite3_bind_double(pStmt, iIndex, fValue);
  27.     }
  28.     static int BindBlob(sqlite3_stmt *pStmt, int iIndex, void const* pData, int iSize)
  29.     {
  30.         return sqlite3_bind_blob(pStmt, iIndex, pData, iSize, NULL);
  31.     }
  32.     ....
  33. };
  34. templateclass TChar >
  35. struct SQLite_APITraits;
  36. template<>
  37. struct SQLite_APITraits<char> : public SQLite_APIBase
  38. {
  39.     static int Open( char const* filename, sqlite3** ppDb)
  40.     {
  41.         return sqlite3_open(filename, ppDb);
  42.     }
  43.     static int BindText(sqlite3_stmt *pStmt, int iIndex, char const* pText, int iSize)
  44.     {
  45.         return sqlite3_bind_text(pStmt, iIndex, pText, iSize, NULL);
  46.     }
  47.     static char const* ErrorMsg(sqlite3* pDB)
  48.     {
  49.         return sqlite3_errmsg(pDB);
  50.     }
  51.     ...........
  52. };
  53. template<>
  54. struct SQLite_APITraits<wchar_t> : public SQLite_APIBase
  55. {
  56.     static int Open( wchar_t const* filename, sqlite3** ppDb)
  57.     {
  58.         return sqlite3_open16(filename, ppDb);
  59.     }
  60.     static int BindText(sqlite3_stmt *pStmt, int iIndex, wchar_t const* pText, int iSize)
  61.     {
  62.         return sqlite3_bind_text16(pStmt, iIndex, pText, iSize, NULL);
  63.     }
  64.     static wchar_t const* ErrorMsg(sqlite3* pDB)
  65.     {
  66.         return sqlite3_errmsg16(pDB);
  67.     }
  68.     ............
  69. };

这样以来,使用SQLite API时方便多了,不必针对char wchar_t调用不同的函数了,现在只需这样SQLite_APITraits<TCHAR>::some_func.

    

    2.数据库层的封装

先来看一下数据库的接口

 

 

  1. class CDatabase  
  2. {
  3. public:
  4.  CDatabase();
  5.  virtual ~CDatabase();
  6. public:
  7.  virtual bool Open(TCHAR const* pszFileName) = 0;
  8.  virtual bool Close() = 0;
  9.  virtual bool Execute(TCHAR const* pszSQLStatement) = 0;
  10. };

CDatabase  提供了3个接口,Open打开数据库文件,Close关闭数据库,Execute执行制定的SQL语句.

 

这些接口的实现主要用到了下面的一些组件CDBConnection类,CDBStatement类,CResultSet类:

其中,CDBConnection负责管理数据库连接,CDBStatement负责运行SQL语句并生成执行结果,最终通过CResultSet查询结果。

为了使得这些组件能在不同的数据库间移植,需要把不同数据库的具体实现能分离出来,这里我用DBTraits模板来分离,为每种数据库实现一个特化版本,关于Traits用法,请参考侯捷老大一篇文章Traits: 類型的else-if-then機製.

(为了不影响代码的连贯性,DBTraits模板的代码附在最后)

下面是各个组件的实现,中间用到了iterator,类似于STL的迭代器但稍稍不同,你将会看到iterator将使得结果查询变得多么简单优雅

 

  1. template<class T, class TDBTraits = DBTraits<T>, 
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 13
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值