TeamTalk客户端源码分析三

版权声明:本文为博主原创文章,如需转载请注明出处 https://blog.csdn.net/bajianxiaofendui/article/details/84945877

     本章介绍数据库相关模块设计及代码。主要的业务逻辑还是在Modules工程中,但是数据库的基本封装是在utility工程中。前者实现了各个业务对应的数据库访问接口封装,后者实现了对sqlite数据库访问的封装。

一,Modules中的数据库业务类

     我们先看Modules中的Database过滤器,IDatabaseModule.h是一个虚基类,还是继承了我们第一篇文章中讲述的ModuleBase类,实现一个观察者模式的回调。DatabaseModule_Impl.h中才实现了真正的操作类,继承于IDatabaseModule。
     整个DatabaseModule_Impl类包含了图片存储相关,最近联系会话信息,用户信息相关,部门信息相关等等程序中涉及到数据库的业务模块,这些业务的数据库操作逻辑都是在这个类里实现的。
在这里插入图片描述
     DatabaseModule_Impl类有两个成员变量m_pSqliteDB和m_pSqliteGlobalDB,都是CppSQLite3DB*类型(封装在utility工程中的数据库接口类)。在Teamtalk中有两种数据库,一种是当前用户的数据库(只有当前用户可以读写),一种是全局使用的数据库(所有用户都可以读写),这两个变量就是分别操作这两种数据库的,具体封装实现稍后再说。
     DatabaseModule_Impl类中同时实现了不同业务的数据库访问接口,它们的声明都在DatabaseModule_Impl.h文件中,但是不同业务的接口定义(实现)在各自的cpp文件中。比如:图片存储相关的放在DatabaseModule_ImageDB_Impl.cpp中;用户信息相关的放在DatabaseModule_UserInfoDB_Impl.cpp中。这样做主要是为了区分业务,避免一个cpp文件中代码量过大,这种一个头文件,多个源文件的处理方式在Teamtalk中比较常见,大家需要注意。
     具体的业务逻辑就不再多介绍,都是一些基本的增删改查数据库的调用,大家看一下代码就明白了。
在这里插入图片描述
     与上一章讲的各个业务功能模块提供的接口访问方式一样,DatabaseModule_Impl对象也是通过一个全局的函数来访问唯一实例。
在这里插入图片描述

二,Sqlite中的数据库访问类

     Teamtalk中使用的数据库是sqlite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。使用起来也非常方便,只需要一个sqlite3.h,一个sqlite3.h,sqlite3.lib,再加上一个sqlite3.dll就可以进行数据库的增删改查操作了,具体的sqlite语法大家可以自己在官网查阅学习(大部分的语法和sqlite是一样的)。
     打开utility工程下的CppSQLite3.h文件,在这里面定义了很多类,但是我们只用关注CppSQLite3DB,CppSQLite3Query,CppSQLite3Statement这三个类,其它的类都是没有用到的(CppSQLite3Exception类比较简单,大家可以自己阅读代码),你如果觉的看的麻烦也可以选择删掉。

1,CppSQLite3Statement

     CppSQLite3Statement有两个成员变量,所有的操作都是通过这两个成员变量来实现的:

  sqlite3* mpDB;	//sqlite具体操作类
  sqlite3_stmt* mpVM;	//sqlite语句类

     比如类中实现了很多bind函数,是对sqlite3_stmt* mpVM字符串类的进一步封装,对于sql语句的参数可以更好地进行填充,而不用再使用format或者sprintf等方式进行填充。
     而且CppSQLite3Statement是专门提供给外部来进行数据库访问操作的,调用处只需要获取到对应的CppSQLite3Statement对象,调用bind()填充参数,最后调用execDML()接口,就可以完成数据库语句的执行。
在这里插入图片描述
     其中,const std::string updateDepartmentBySIdSql = "update departmentinfo set dId=?,priority=?,name=?,departmentId=?,parentDepartId=?,status=? where dId=?";

2,CppSQLite3Query

     CppSQLite3Query是用来处理数据库查询结果的,增删改查这几种操作,增删改都是可以直接通过数据库执行语句的返回值来判断操作的结果:成功或者失败。但是对于查询,我们还需要得到查询的结果,CppSQLite3Query类就是实现这个功能的。
在这里插入图片描述
     在执行完sql语句后,直接用sqlite3对象和sqlite3_stmt对象创建一个CppSQLite3Query对象,做一个传参作用。在CppSQLite3Query中有很多函数取值函数,可以通过这些函数来获取到对应的查询结果:

    int getIntField(int nField, int nNullValue=0);
    int getIntField(const char* szField, int nNullValue=0);

	sqlite_int64 getInt64Field(int nField, sqlite_int64 nNullValue=0);
	sqlite_int64 getInt64Field(const char* szField, sqlite_int64 nNullValue=0);

    double getFloatField(int nField, double fNullValue=0.0);
    double getFloatField(const char* szField, double fNullValue=0.0);

    const char* getStringField(int nField, const char* szNullValue="");
    const char* getStringField(const char* szField, const char* szNullValue="");

    const unsigned char* getBlobField(int nField, int& nLen);
    const unsigned char* getBlobField(const char* szField, int& nLen);

     这些函数的内部最终也都是调用sqlite的接口实现的
在这里插入图片描述
     对于查询结果不止一条的时候,可以调用CppSQLite3Query::nextRow()函数进行循环,循环终止条件为:
在这里插入图片描述
     mbEof的赋值就是在每次调用nextRow()的时候看是否执行到了最后一条结果,如果是,那么mbEof = true;
     具体的使用可以看DatabaseModule_Impl::sqlGetAllDepartmentInfo函数。
在这里插入图片描述

3,CppSQLite3DB

     CppSQLite3DB是真正操作数据库的类,它的内部封装了sqlite的接口类sqlite3*,所有的数据库操作,包括打开数据库,执行数据库语句,都是通过CppSQLite3DB类中的sqlite3* mpDB对象实现的。
在这里插入图片描述
     一个CppSQLite3DB对象对应一个数据库,所以在我们Modules工程中的DatabaseModule_Impl类中有两个CppSQLite3DB*,一个是当前用户的数据库,一个是全局的数据库。因为DatabaseModule_Impl是一个单例,所以全局也只有两个CppSQLite3DB对象。

结束语:使用第三方库的时候,一定要加上异常捕捉机制。因为这些都没有提供源码,你也不清楚代码的编写是否规范,是否会导致程序崩溃,所以,最好加上异常捕捉机制,在异常处加上自己的日志打印,便于查找问题。

猜你喜欢

转载自blog.csdn.net/bajianxiaofendui/article/details/84945877