使用sqlite3数据库在嵌入式系统中作为本地状态机,替代以往使用一系列配置文件作为本地状态存储是一种结构化程度更强的方式。

要访问sqlite3数据库,首先要建立本地状态机对应的多个表,然后构造sql语句,调用sqlite_exec进行Insert/Update/Delete操作(DML),得到所需的结果或者结果集。不论是Insert/Update/Delete任何一种DML的操作,sqlite_open, sqlite_exec, sqlite_close的模式总是相同的,因此可以将这个模式抽象成一个类。

以下是我在一个项目中对DML进行抽象,得到的一个dsn类。这个类包括头文件tvn_dsn.h和实现体tvn_dsn.cpp,代码如下所示。

tvn_dsn.h:其中将具体的文件名称路径用xxx替代了。

/*** =============================================================* @file     .../app/statemachine/dml/tvn_dsn.h* @author   Luoyuan (15904113750@163.com)* @brief    Topview Networks SQLite3 Common header file* @version  1.0.0* @date     2021-12-16** @copyright Copyright (c) 2020-2022, Topview Networks* @remark    * =============================================================*/#ifndef _TVN_SQLITE3_DSN_H_
#define _TVN_SQLITE3_DSN_H_#define TVN_MAX_EM_LEN 64
#define TVN_MAX_SQL_LEN 4096
#define TVN_MAX_TXT_LEN 512
#define TVN_DML_RETRY 32
#define TVN_DML_RETRY_INTERVAL 50057#define TVN_DSN_OK 0
#define TVN_DSN_ERROR 1
#define TVN_DSN_MTX_FAILED 5#include "./sqlite3.h"
#include <string>
#include "../../utils/tvn_g.h"#ifdef _AMD64_
#define NVRAM_DB_FILE "/home/xxx/nvram"
#define STMACH_DB_SOURCE_FILE "/home/xxx/stmach"
#else
#define NVRAM_DB_FILE "/usr/bin/myapp/nvram"
#define STMACH_DB_SOURCE_FILE "/usr/bin/myapp/stmach"
#endif
#define STMACH_DB_FILE "/tmp/stmach"typedef SQLITE_API int DBRES;
typedef sqlite3 *DB;
typedef char EM[TVN_MAX_EM_LEN + 1];using namespace std;class TVN_DSN
{
private:string dbFileName;DB db;int isOpen;int nvrIsOpen, stmIsOpen;int ac;string err;public:TVN_DSN();TVN_DSN(const TVN_DSN &v);~TVN_DSN();void Open(const char *vDBFileName);int OpenNvram();int OpenStatemachine();int IsOpen() const { return isOpen; }int NvramIsOpen() const { return nvrIsOpen; }int StatemachineIsOpen() const { return stmIsOpen; }void Close();int Read(const char *sql,int (*callback)(void *, int, char **, char **),void *res,char **errmsg);int Write(const char *sql,char **errmsg);void Debug(const string who,const char *sql,const int ac,const string err);int ExRead(const char *sql,int (*callback)(void *data, int argc, char **argv, char **azColName),void *dc,char **errMsg);int ExWrite(const char *sql,char **errMsg);int ForceWrite(const char *sql, char **errMsg);DB Me() const { return db; }int ActionCode() const { return ac; }string Error() const { return err; }
};#endif // _TVN_SQLITE3_DSN_H_

tvn_dsn.cpp:

/*** =============================================================* @file     .../app/statemachine/dml/tvn_dsn.cpp* @author   Luoyuan (15904113750@163.com)* @brief    Topview Networks SQLite3 Implementation* @version  1.0.1* @date     2021-12-16** @copyright Copyright (c) 2020-2022, Topview Networks* @remark    * =============================================================*/#include <unistd.h>
#include <pthread.h>
#include "./tvn_dsn.h"
#include "../../utils/tvn_g.h"
#include "../../utils/tvn_color.h"pthread_mutex_t mtxDbWrite;TVN_DSN::TVN_DSN()
{db = 0;isOpen = 0;nvrIsOpen = 0;stmIsOpen = 0;ac = TVN_DSN_OK;err = "";
}TVN_DSN::TVN_DSN(const TVN_DSN &v)
{db = v.Me();isOpen = v.IsOpen();nvrIsOpen = v.NvramIsOpen();stmIsOpen = v.StatemachineIsOpen();ac = v.ActionCode();err = v.Error();
}TVN_DSN::~TVN_DSN()
{if (isOpen)Close();
}void TVN_DSN::Open(const char *vDBFileName)
{isOpen = 0;// ac = sqlite3_open_v2(vDBFileName, &db, SQLITE_OPEN_READWRITE, NULL);ac = sqlite3_open_v2(vDBFileName, &db, SQLITE_OPEN_FULLMUTEX | SQLITE_OPEN_READWRITE, NULL);// ac = sqlite3_open(vDBFileName, &db);if (SQLITE_OK != ac){err = sqlite3_errmsg(db);return;}dbFileName = vDBFileName;isOpen = 1;
}int TVN_DSN::OpenNvram()
{Open(NVRAM_DB_FILE);isOpen = 1;nvrIsOpen = 1;return ac;
}int TVN_DSN::OpenStatemachine()
{Open(STMACH_DB_FILE);isOpen = 1;stmIsOpen = 1;return ac;
}void TVN_DSN::Close()
{if (db){sqlite3_close_v2(db);db = 0;#if (_DBG_B0_)printf("[TVN_DSN::Close()] Database %s closed accordingly.\r\n", dbFileName.c_str());
#endif}isOpen = 0;nvrIsOpen = 0;stmIsOpen = 0;
}int TVN_DSN::Read(const char *sql,int (*callback)(void *, int, char **, char **),void *res,char **errmsg)
{int rc = SQLITE_ABORT;err = "";pthread_mutex_lock(&mtxDbWrite);rc = sqlite3_exec(db, sql, callback, res, errmsg);pthread_mutex_unlock(&mtxDbWrite);if (*errmsg)err = *errmsg;return rc;
}int TVN_DSN::Write(const char *sql,char **errmsg)
{int rc = SQLITE_ABORT;err = "";pthread_mutex_lock(&mtxDbWrite);rc = sqlite3_exec(db, sql, NULL, NULL, errmsg);pthread_mutex_unlock(&mtxDbWrite);if (*errmsg)err = *errmsg;return rc;
}int TVN_DSN::ExRead(const char *sql,int (*callback)(void *data, int argc, char **argv, char **azColName),void *dc,char **errMsg)
{int ac = SQLITE_EMPTY;int retries = TVN_DML_RETRY;do{ac = Read((char *)sql, callback, dc, errMsg);if (ac != SQLITE_OK){retries--;usleep(TVN_DML_RETRY_INTERVAL);}else{break;}
#if (_DBG_B1_)printf(WHITE"[TVN_DSN::ExRead]\r\n""    sql= %s\r\n""retries= %d\r\n""     ac= %d\r\n""    err= %s" NONE "\r\n",sql, retries, ac, *errMsg);
#endif} while (SQLITE_OK != ac && retries > 0);return ac;
}int TVN_DSN::ExWrite(const char *sql,char **errMsg)
{int ac = SQLITE_EMPTY;int retries = TVN_DML_RETRY;do{ac = Write(sql, errMsg);if (SQLITE_OK != ac){retries--;usleep(TVN_DML_RETRY_INTERVAL);}else{break;}#if (_DBG_B1_)printf(WHITE"[TVN_DSN::ExWrite]\r\n""    sql= %s\r\n""retries= %d\r\n""     ac= %d\r\n""    err= %s" NONE "\r\n",sql, retries, ac, *errMsg);
#endif} while (SQLITE_OK != ac && retries > 0);return ac;
}int TVN_DSN::ForceWrite(const char *sql, char **errMsg)
{int ac = SQLITE_EMPTY;do{ac = Write(sql, errMsg);if (SQLITE_OK != ac){usleep(TVN_DML_RETRY_INTERVAL);}} while (SQLITE_OK != ac);return ac;
}void TVN_DSN::Debug(const string who,const char *sql,const int ac,const string err)
{printf(L_RED"%s:\r\n""  SQL = %s\r\n""   ac = %d\r\n""  Err = %s" NONE "\r\n",who.c_str(), sql, ac, err.c_str());
}

说明:

  1. tvn_dsn.h定义了默认构造函数和拷贝构造函数,在默认构造函数中对其私有变量进行了初始化。
  2. Open,OpenNvram和OpenStatemachine三个方法用于封装sqlite3_open_v2函数,而sqlite3_close_v2()在类的析构函数中执行。OpenNvram()方法和OpenStatemachine()方法都调用Open()方法,只不过这两个方法固定了dbFileName,这样做,使得外部调用时就不必每一次都显示地携带dbFileName参数,上层调用得到了简化。
  3. Read和Write方法是基本的实现,封装了sqlite3_exec。
  4. ExRead和ExWrite循环调用Read/Write方法,当存在多线程访问时,提升容错性。
  5. ForceWrite确保某些关键信息必须写入成功。
  6. mtxDbWrite锁用于应用层的读写,在多线程访问时,保证写的独占性。简单起见,读和写共用了一个锁。

调用方法较为简单,结合代码说明。

调用1:单记录读

int TopoInfoBean::Get(string vMAC)
{if (vMAC.empty()){ac = SQLITE_NULL;err = "[TopoInfoBean].Get(string)  Parameter MAC empty.";return ac;}char *zErrMsg = 0;char sql[TVN_MAX_SQL_LEN] = "";sprintf(sql, "SELECT "" mac"",tei"",proxyTEI"",level"",ability"",snr"",attenuation"",phase ""FROM TopoInfo"" WHERE mac='%s'",vMAC.c_str());dsn.OpenStatemachine();ac = dsn.ExRead(sql, selProcessor, (void *)(this), &zErrMsg);dsn.Close();err = (SQLITE_OK == ac) ? "" : zErrMsg;sqlite3_free(zErrMsg);if (SQLITE_OK != ac){dsn.Debug("[TopoInfoBean].Get(vMAC)", sql, ac, err.c_str());}return ac;
}

说明:上述方法按照特定的MAC地址查询TopoInfo,首先进行了一个空值判断,然后构造sql语句,使用dsn打开数据库,调用Read/ExRead方法,通过sqlProcessor回调函数得到结果记录。后面是调试语句了。

调用2:多记录读

vector<TopoInfoBean> TopoInfoBean::All()
{vector<TopoInfoBean> res;char *zErrMsg = 0;char sql[] = "SELECT"" mac"",tei"",proxyTEI"",level"",ability"",snr"",attenuation"",phase"" FROM TopoInfo"" ORDER BY tei ASC";dsn.OpenStatemachine();ac = dsn.ExRead(sql, selProcMulti, (void *)(&res), &zErrMsg);dsn.Close();err = (SQLITE_OK == ac) ? "" : zErrMsg;sqlite3_free(zErrMsg);if (SQLITE_OK != ac){dsn.Debug("[TopoInfoBean].GetAll()", sql, ac, err.c_str());res.clear();}return res;
}

说明:和单记录读略有不同的是,多记录读在Read方法中使用的回调函数的第三个参数传递的是结果集的地址,而单记录读的对应参数是TopoInfoBean本身(this)。回调函数也将不同。

调用3:写

int TopoInfoBean::Insert()
{char *zErrMsg = 0;char sql[TVN_MAX_SQL_LEN] = "";sprintf(sql, "INSERT INTO TopoInfo ""(mac"",tei"",proxyTEI"",level"",ability"",snr"",attenuation"",phase) VALUES ""('%s'"",%d"",%d"",%d"",'%s'"",%d"",%d"",%d);",mac.c_str(),tei,proxyTEI,level,ability.c_str(),snr,attenuation,phase);dsn.OpenStatemachine();ac = dsn.ExWrite(sql, &zErrMsg);dsn.Close();err = (SQLITE_OK == ac) ? "" : zErrMsg;sqlite3_free(zErrMsg);if (SQLITE_OK != ac)dsn.Debug("[TopoInfoBean].Insert()", sql, ac, err.c_str());return ac;
}

说明:Write/ExWrite方法的参数只有两个,不需要调用回调函数。

使用C++将sqlite3数据库访问封装成dsn类相关推荐

  1. writeValueAsString封装成工具类

    封装成工具类 [java] view plaincopyprint? <span style="font-family:Microsoft YaHei;">public ...

  2. 直播项目之 将SDK提供的C 头文件,封装成C++类 管理

    一:封装前准备 以网易直播SDK为例解析,将其封装成一个类,便于管理. 提供了 SDK/include目录: 存放直播推流 SDK API的头文件.             SDK/lib目录: 存放 ...

  3. 关于excel导入到封装成工具类jar包和web版门店收银网络无法无法连接上的解决方法...

    2011-12-4 1.excel导入工具封装碰到如何给传输过来的泛型对象进行对象点Setter的方法,解决方法应该可以查看struts2框架的源码查看他在拦截器作用下是怎么给action这个类的一个 ...

  4. 基于SqlSugar的数据库访问处理的封装,支持多数据库并使之适应于实际业务开发中

    Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/cou ...

  5. [课程][原创]yolox检测封装成类调用几句代码完成目标检测任务

    搞定系列:yolox检测封装成类调用 课程地址:搞定系列:yolox检测封装成类调用--深度学习视频教程-人工智能-CSDN程序员研修院 你将收获 1.学会Yolox封装基本技巧和大体思路 2.学会Y ...

  6. C语言使用 ASN.1对报文进行编解码(将c函数封装成类简化使用)

    文章目录 1.为什么要报文编解码 2.ASN.1是什么 3.使用函数介绍 4.对数据进行编解码 5.C语言使用 6.将上述函数封装成c++类 1.为什么要报文编解码 两台机器通信: 1.两台机器的操作 ...

  7. SpringBoot 封装 HBase 操作工具类

    最近项目中用到了Hbase相关的操作并封装成工具类,我的Hbase服务器端版本是2.1.0,图示如下: 特此记录便于日后查阅. 一.pom.xml 依赖 <dependency><g ...

  8. 效果很好的asp.net的数据库访问模型(优化,封装一体化)

    效果很好的asp.net的数据库访问模型(优化,封装一体化) 非常有效的数据库/配置文件访问模型.成功使用在几万流量的网站上.任何建议欢迎大家交流. 在使用SqlCommand对象过程中,我们需要分配 ...

  9. 【使用SqliteSpy访问Sqlite3数据库】

    软件准备 sqlite3数据库:SQLiteSpy,图形化访问sqlite3数据库,建表,执行SQL语句:新建空文件夹,例如E:\demo0525_testsqlite3,存放数据库文件及程序驱动. ...

最新文章

  1. stagefright框架概述
  2. Python模块之间的相互引用问题
  3. printf 和sprintf
  4. householder变换qr分解matlab_【基础教程】Matlab实现傅里叶变换
  5. 配置 Powerline 到 Vim
  6. 智能情绪分析技术_简单分析人工智能的表现在计算机网络应用技术中的优势
  7. 信息学奥赛一本通(1113:不与最大数相同的数字之和)
  8. 华图砖题库php文件怎么打印_事业单位招聘考试《工会基础知识》试题库及答案1380题...
  9. golang基础语法
  10. Office 2007在安装过程中出错
  11. 空格表示 java_java 正则表达式 空格怎么表示
  12. H5-表格的基本样式
  13. 移动服务器位置,移动协同服务器地址是怎么设置
  14. 一步一步分析Gin框架路由源码及radix tree基数树
  15. 开头th_是什么文件_以th开头的英文单词th开头的所有英文单词
  16. 职场最高级的聪明是靠谱,到底一个人怎样才算真正靠谱?
  17. 【Linux】Ubuntu运行环境搭建
  18. 席绢言情系列书评总序
  19. 电脑调分辨率黑屏了怎么办_电脑调分辨率黑屏了怎么办
  20. 聊一位倾慕已久的他——致敬图灵

热门文章

  1. 13-cmake语法-路径设置
  2. 照片相框软件有什么?照片相框怎么加技巧分享
  3. socket:10038错误
  4. 浅谈slf4j,logger中的{}功能
  5. 从事Web前端要学什么 常用前端开发技术有哪些
  6. 伟大的领导者要做到四件事(整理自《领导力精要》史蒂芬.柯维)
  7. CSS transform属性
  8. MPC5746C双核启动配置分析
  9. 注意力机制在推荐模型中的应用——AFM、DIN、DIEN
  10. 虚拟机安装linux