libdbclient接口介绍

    这是一个神奇的开发接口!

    它支持mysql, sqlite, 达梦和oracle这四款数据库的访问!

    它对外提供统一的C++抽象接口,隐藏内部具体的实现细节,对于使用者学习成本为0!

    它提供抽象的结果表对象(result_table)和结果集对象(result_set),满足不同使用者的使用习惯!

     它目前只能工作在Linux(x86_64)平台下,还不支持跨平台,还在继续开发和维护中。

     好了,有没有引起你的一丢丢好奇呢?下面我们就来掀开它那神奇的面纱:

/*
 * 文件名:
 *      db_client.h
 *
 * 作  用:
 *      数据库操作接口(支持国产达梦数据库, mysql数据库, sqlite数据库和oracle数据库)
 *
 * 介  绍:
 *      1. 封装了达梦数据库的DPI接口;
 *      2. 封装了mysql数据库的C接口;
 *      3. 封装了sqlite数据库的sqlite3接口;
 *      4. 封装了oracle数据库的oci(使用ocilib)接口;
 *      5. 支持连接断线自动重连(mysql和达梦. oracle使用的是ocilib提供的pool,不清楚是否提供断线自动重连);
 *      6. 提供数据库连接池功能(sqlite不提供此功能,但接口与其他数据库一致);
 *      7. 向用户层提供统一的c++访问接口, 隐藏具体的数据库细节;
 *      8. 提供常用的数据类型访问(TEXT(CHAR,VARCHAR,NVARCHAR,TEXT), SHORT(2), INT(4), LONG(8), FLOAT, DOUBLE, TIMESTAMP和BLOB等基础类型操作);
 *      9. 提供抽象的结果表对象(result_table)和结果集对象(result_set),满足不同的使用习惯;
 *
 * 作  者
 *      shenyi(E-mail: shenyi0106@163.com  QQ: 52851771)
 *
 * 时  间:
 *     2019/11/25
 *
 * 依  赖:
 *     libdmdpi.so(达梦DPI接口库)
 *     libmysqlclient.so
 *     libsqlite3.so
 *     libocilib.so(ORACLE, 依赖OCI接口库)
 *
 * 版  权:
 *
 */
#ifndef DB_CLIENT_H
#define DB_CLIENT_H
#include <string>
#include <vector>

#ifndef UNUSED
#define UNUSED(x) (void)(x)
#endif

#ifndef MIN
#define MIN(x,y) (x) > (y) ? (y) : (x)
#endif

#ifndef MAX
#define MAX(x,y) (x) > (y) ? (x) : (y)
#endif

//
// 支持的底层数据库接口
//
enum DB_CLIENT_TYPE
{
    DB_CLIENT_TYPE_DAMO   = 1,   // 达梦
    DB_CLIENT_TYPE_MYSQL  = 2,   // MYSQL
    DB_CLIENT_TYPE_SQLITE = 3,   // SQLITE3
    DB_CLIENT_TYPE_ORACLE = 4,   // ORACLE(OCI)
};

//
// 支持的数据类型(目前访问接口只支持以下几种数据类型)
//
enum DATA_TYPE
{
    DATA_CTYPE_NULL      = -1,
    DATA_CTYPE_STRING    = 0,
    DATA_CTYPE_SSHORT    = 1,
    DATA_CTYPE_USHORT    = 2,
    DATA_CTYPE_SLONG     = 3,
    DATA_CTYPE_ULONG     = 4,
    DATA_CTYPE_FLOAT     = 5,
    DATA_CTYPE_DOUBLE    = 6,
    DATA_CTYPE_BLOB      = 12,
    DATA_CTYPE_SINT      = 13,
    DATA_CTYPE_UINT      = 14,
    DATA_CTYPE_TIMESTAMP = 15,
};

//
// 日志级别
// 数字越高,级别越高; 较低的日志级别可以包含较高的日志级别的日志,反之却不行.
// 例如:
//   1. 设置了DBG_LEVEL_DEBUG, 系统大于等于DBG_LEVEL_DEBUG的日志都可以被打印出来(全部日志);
//   2. 设置了DBG_LEVEL_WARN, 系统只能打印DBG_LEVEL_WARN和DBG_LEVEL_ERROR这两个级别的日志;
//
enum DBG_LEVEL
{
    DBG_LEVEL_DEBUG  = 1,
    DBG_LEVEL_INFO   = 4,
    DBG_LEVEL_WARN   = 8,
    DBG_LEVEL_ERROR  = 16,
};

//
// 缺省数据库连接和执行超时时间
//
#define DEFAULT_TIMEOUT_SECOND 2

//
// 使用stmt模式下,可用的最大参数数量
//
#define MAX_BIND_PARAM_COUNT 64

//
// stmt模式下的参数结构
//
struct bind_param
{
#if SUPPORT_ORACLE
    char           name[64];  // 参数名称(表示参数名称,ocilib不支持按索引绑定参数模式)
    void          *lob;       // 内部函数中使用,调用者请忽略此参数
#endif
    void          *buffer;    // 指向缓冲区的指针
    long           buf_type;  // 参数类型, DATA_TYPE中的一个
    unsigned long  buf_size;  // 缓冲区大小
    unsigned long  buf_len;   // 参数的长度
};


//
// 结果集内存表
// 将查询结果在内存中构建成一个schema, 可以像二维表格一样随机访问任意一个单元数据
//
class result_table
{
public:
    //
    // 获得纪录集行数
    //
    virtual int get_row_count() = 0;

    //
    // 获得纪录集列数量
    //
    virtual int get_col_count() = 0;


    //
    // 读取字段的string值
    // col : 基于0的列索引
    // name: 列名称(不区分大小写)
    //
    virtual bool get_string_value(int row, int col, std::string &val) = 0;
    virtual bool get_string_value(int row, std::string name, std::string &val) = 0;

    //
    // 读取字段的string值(通过返回值的形式)
    // col : 基于0的列索引
    // name: 列名称(不区分大小写)
    //
    virtual std::string get_string_value(int row, int col) = 0;
    virtual std::string get_string_value(int row, std::string name) = 0;

    //
    // 读取字段的short值(16位)
    // col : 基于0的列索引
    // name: 列名称(不区分大小写)
    //
    virtual bool get_short_value(int row, int col, short &val) = 0;
    virtual bool get_short_value(int row, std::string name, short &val) = 0;

    //
    // 读取字段的int值(32位)
    // col : 基于0的列索引
    // name: 列名称(不区分大小写)
    //
    virtual bool get_int_value(int row, int col, int &val) = 0;
    virtual bool get_int_value(int row, std::string name, int &val) = 0;

    //
    // 读取字段的long值(64位)
    // col : 基于0的列索引
    // name: 列名称(不区分大小写)
    //
    virtual bool get_long_value(int row, int col, long &val) = 0;
    virtual bool get_long_value(int row, std::string name, long &val) = 0;

    //
    // 读取字段的float值
    // col : 基于0的列索引
    // name: 列名称(不区分大小写)
    //
    virtual bool get_float_value(int row, int col, float &val) = 0;
    virtual bool get_float_value(int row, std::string name, float &val) = 0;

    //
    // 读取字段的double值
    // col : 基于0的列索引
    // name: 列名称(不区分大小写)
    //
    virtual bool get_double_value(int row, int col, double &val) = 0;
    virtual bool get_double_value(int row, std::string name, double &val) = 0;

    //
    // 读取字段的二进制内容
    // col : 基于0的列索引
    // name: 列名称(不区分大小写)
    //
    // val : 输出参数, 指向二进制缓冲区
    // ret_len: 输出参数, 二进制缓冲区长度
    //
    //
    virtual bool get_blob_value(int row, int col, void **val, int *ret_len) = 0;
    virtual bool get_blob_value(int row, std::string name, void **val, int *ret_len) = 0;

    //
    // 读取字段的日期时间
    // col : 基于0的列索引
    // name: 列名称(不区分大小写)
    //
    // tv : 输出参数, 日期结构
    //
    virtual bool get_datetime_value(int row, int col, struct tm *tv) = 0;
    virtual bool get_datetime_value(int row, std::string name, struct tm *tv) = 0;
};

//
// 结果集操作接口
// 可通过此接口来顺序获取各行和各列的数据
//
class result_set
{
public:
    //
    // 读取下一行
    //
    virtual bool fetch_row() = 0;

    //
    // 获得纪录集行数
    //
    // 注意:
    //     达梦数据库此接口无效! 仅当fetch_row到最后一行时,此接口才有效.
    //     SQLITE此接口无效!
    //
    virtual int  get_row_count() = 0;

    //
    // 获得纪录集列数量
    //
    virtual int  get_col_count() = 0;

    //
    // 读取字段值数据(基础接口)
    //
    // ctype : 输入参数, 读取的字段类型; DATA_TYPE中的一个;
    // val   : 输出参数, 读取字段内容将存放到缓冲区中
    // buf_len: 输入参数, 缓冲区val的大小
    // ret_len: 输出参数, 字段内容大小(可以为nullptr,表示不关心返回长度)
    //
    // 备注:
    //    当val==nullptr且buf_len==0, 而ret_len!=nullptr, 则返回所读字段的长度;
    //
    virtual bool get_value(int col, int ctype, void *val, int buf_len, int *ret_len) = 0;

    //
    // 读取字段的字符串值
    //
    // val: 输出参数
    //
    virtual bool get_string_value(int col, std::string &val) = 0;

    //
    // 读取字段的字符串值(通过返回值形式)
    //
    virtual std::string get_string_value(int col) = 0;

    //
    // 读取字段的short值(16位)
    //
    // val: 输出参数
    //
    virtual bool get_short_value(int col, short &val) = 0;

    //
    // 读取字段的int值(32位)
    //
    // val: 输出参数
    //
    virtual bool get_int_value(int col, int &val) = 0;

    //
    // 读取字段的long值(64位)
    //
    // val: 输出参数
    //
    virtual bool get_long_value(int col, long &val) = 0;

    //
    // 读取字段的float值
    //
    // val: 输出参数
    //
    virtual bool get_float_value(int col, float &val) = 0;

    //
    // 读取字段的double值
    //
    // val: 输出参数
    //
    virtual bool get_double_value(int col, double &val) = 0;

    //
    // 读取字段的二进制数据
    //
    // val    : 输出参数, 存放二进制数据的缓冲区
    // buf_len: 输入参数, 缓冲区val的大小
    // ret_len: 输出参数, 读取的二进制数据的长度
    //
    virtual bool get_blob_value(int col, void *val, int buf_len, int *ret_len) = 0;

    //
    // 读取字段的日期时间值
    //
    // val: 输出参数
    //
    virtual bool get_datetime_value(int col, struct tm *val) = 0;
};

//
// 数据库连接
// 表示一条数据库连接, 通过此对象可以执行数据的增删改查操作;
// 所有的execute_*接口都是线程安全的
//
class connection
{
public:
    //
    // 释放连接到连接池
    // 作用等同于connect_pool::close()
    //
    virtual void close() = 0;

    //
    // 查询数据
    // 返回结果集操作对象
    //
    // 备注:
    //    请使用free_result_set接口释放结果集操作对象,否则会导致严重的内存泄露
    //
    virtual result_set* execute_query(const char *sql, ...) = 0;
    virtual result_set* execute_query(std::string sql) = 0;
    virtual void free_result_set(result_set **result) = 0;

    //
    // 查询数据
    // 返回结果集内存表
    //
    // 备注:
    //    1. 请使用free_data_table接口释放结果集内存,否则会导致严重的内存泄露;
    //    2. 此接口会依据结果集操作对象(result_set),在内存中构建相关schema数据结构,
    //       所以请不要在查询大数据集时使用此接口,否则可能导致无可用内存的情况出现;
    //    3. 推荐使用环境: 在查询数据集<=1000条, 使用此接口
    //
    virtual result_table* execute_query2(const char *sql, ...) = 0;
    virtual result_table* execute_query2(std::string sql) = 0;
    virtual void free_data_table(result_table **table) = 0;

    //
    // 执行INSERT, DELETE, UPDATE语句接口
    //
    virtual bool execute_update(const char *sql, ...) = 0;
    virtual bool execute_update(std::string sql) = 0;
    virtual bool execute_update(std::vector<std::string> sqls) = 0;

    //
    // 通过stmt模式,绑定参数执行数据更新操作
    // param : 参数集合(param[])
    // size  : 参数集合param数量
    //
    virtual bool execute_bind(const char *sql, struct bind_param *param, int size) = 0;

    //
    // 连接是否有效
    //
    // 备注:
    //   此接口无效(保留以后使用)
    //
    virtual bool is_open() = 0;

    //
    // 事务相关
    //
    // 备注:
    //    以下三个接口对sqlite无效!
    //
    virtual bool set_auto_commit(bool enable) = 0;
    virtual bool commit() = 0;
    virtual bool rollback() = 0;
};

//
// 数据库连接池
// 初始化一定数量的数据库连接保持在系统中,可以提高数据库访问效率
//
class connection_pool
{
public:
    //
    // 作用等同于connect中的同名函数
    // 目的是减少应用层申请和释放连接的步骤
    //
    virtual result_set* execute_query(const char *sql, ...) = 0;
    virtual result_set* execute_query(std::string sql) = 0;
    virtual void free_result_set(result_set **result) = 0;

    //
    // 作用等同于connect中的同名函数
    // 目的是减少应用层申请和释放连接的步骤
    //
    virtual result_table* execute_query2(const char *sql, ...) = 0;
    virtual result_table* execute_query2(std::string sql) = 0;
    virtual void free_data_table(result_table **table) = 0;

    //
    // 作用等同于connect中的同名函数
    // 目的是减少应用层申请和释放连接的步骤
    //
    virtual bool execute_update(const char *sql, ...) = 0;
    virtual bool execute_update(std::string sql) = 0;
    virtual bool execute_update(std::vector<std::string> sqls) = 0;

    //
    // 作用等同于connect中的同名函数
    // 目的是减少应用层申请和释放连接的步骤
    //
    virtual bool execute_bind(const char *sql, struct bind_param *param, int size) = 0;

    //
    // 连接池类型
    // DB_CLIENT_TYPE枚举中的一个
    //
    virtual int      dbtype() = 0;

    //
    // 从连接池中获取一个连接对象
    //
    // 返回值:
    //   成功返回 connect对象; 失败返回nullptr;
    //
    // 备注:
    //  当连接对象使用完后, 必须要使用close接口释放连接对象,
    //  否则会造成连接池耗尽,无连接可用.
    //
    virtual connection* open() = 0;

    //
    // 释放一个连接对象到连接池中
    //
    // conn: 连接对象
    //
    virtual void     close(connection *conn) = 0;
};

//
// 本地导出接口
//
extern "C"
{
    /*
      功 能:
           设置接口库中日志的打印级别
      参 数:
           level: 日志级别, DBG_LEVEL中的一个;
      返回值:
           无
      备  注:
           接口库的默认日志级别是DBG_LEVEL_DEBUG;
    */
    void db_client_set_debug(int level);

    /*
      功 能:
           创建创建数据库连接池对象
      参 数:
           dbtype  :  数据库类型, DB_CLIENT_TYPE中的一个;
           host    :  数据库访问地址(IP形式);
           port    :  数据库的访问端口;
           name    :  要创建的数据库名称(必须是英文名);
           user    :  访问数据库的用户名
           passwd  :  访问数据库的密码
           pool_num:  指定连接池中连接的数量
     返回值:
           成功返回连接池对象, 失败返回nullptr
     备  注:
           1. 当前只支持DB_CLIENT_TYPE中所列的数据库;
           2. 连接池不再使用时,请使用db_client_destory_pool释放对象;
           3. 此连接池中的连接数量为"一次成型", 即创建连接池时一并把指定的连接数量创建完毕,
              使用过程中,不会根据业务请求量自动添加或者删除连接;
           4. 参数使用介绍:
             +-----------------------+-------------+-------------+-------------+-------------+-------------+-------------+
             |         dbtype        |     host    |     port    |     name    |     user    |    passwd   |   pool_num  |
             +-----------------------+-------------+-------------+-------------+-------------+-------------+-------------+
             | DB_CLIENT_TYPE_DAMO   |     IP地址   |     端口    |     忽略     |     用户名  |    密码      |  最大连接数  |
             +-----------------------+-------------+-------------+-------------+-------------+-------------+-------------+
             | DB_CLIENT_TYPE_MYSQL  |     IP地址   |     端口    |   数据库名称  |     用户名  |    密码      |  最大连接数  |
             +-----------------------+-------------+-------------+-------------+-------------+-------------+-------------+
             | DB_CLIENT_TYPE_SQLITE |    文件全路径 |     忽略    |     忽略     |     忽略    |    忽略      |    忽略     |
             +-----------------------+-------------+-------------+-------------+-------------+-------------+-------------+
             | DB_CLIENT_TYPE_ORACLE |    TNS名称   |     忽略    |     忽略     |     用户名   |   密码      |  最大连接数  |
             +-----------------------+-------------+-------------+-------------+-------------+-------------+-------------+
    */
    connection_pool* db_client_create_pool(int dbtype, const char *host, int port, const char *name,
                                            const char *user, const char *passwd, int pool_num);

    /*
     功能:
           一组db_client_create_pool相关的宏定义, 用于简化创建数据库连接池的步骤.
     备注:
           具体参数用法请参照db_client_create_pool函数中有关"参数使用介绍"章节
    */
    #define  db_client_create_pool_mysql(host, port, name, user, passwd, pool) db_client_create_pool(DB_CLIENT_TYPE_MYSQL,  host, port, name,    user,    passwd,  pool)
    #define  db_client_create_pool_damo(host, port, user, passwd, pool)        db_client_create_pool(DB_CLIENT_TYPE_DAMO,   host, port, nullptr, user,    passwd,  pool)
    #define  db_client_create_pool_sqlite(path)                                db_client_create_pool(DB_CLIENT_TYPE_SQLITE, path, 0,    nullptr, nullptr, nullptr, 0   )
    #define  db_client_create_pool_oracle(host, user, passwd, pool)            db_client_create_pool(DB_CLIENT_TYPE_ORACLE, host, 0,    nullptr, user,    passwd,  pool)

    /*
     功 能:
           释放数据库连接池对象
     参 数:
            pool  :  数据库连接池对象
     返回值:
            返回0(忽略返回值)

     备  注:
            请参考db_client_create_pool接口说明.
    */
    int db_client_destory_pool(connection_pool *pool);
}

#endif // DB_CLIENT_H

  它导出三个重要的C接口,这三个接口是这个接口库的入口,更是它的灵魂。下面我们来分别介绍着三个重要的接口:

/*
  功 能:
       设置接口库中日志的打印级别
  参 数:
       level: 日志级别, DBG_LEVEL中的一个;
  返回值:
       无
  备  注:
       接口库的默认日志级别是DBG_LEVEL_DEBUG;
*/
void db_client_set_debug(int level);

    此接口用来设置开发库中能够输出的日志级别。 

    libdbclient开发库中添加了许多日志调试信息,使用了不同的日志级别来控制,可以通过这个接口设置需要输出的日志级别,来控制开发接口输出你所需要的调试信息。开发接口默认的日志级别是DBG_LEVEL_DEBUG,也就是说,它会将所有日志都输出出来。

/*
      功 能:
           创建创建数据库连接池对象
      参 数:
           dbtype  :  数据库类型, DB_CLIENT_TYPE中的一个;
           host    :  数据库访问地址(IP形式);
           port    :  数据库的访问端口;
           name    :  要创建的数据库名称(必须是英文名);
           user    :  访问数据库的用户名
           passwd  :  访问数据库的密码
           pool_num:  指定连接池中连接的数量
     返回值:
           成功返回连接池对象, 失败返回nullptr
     备  注:
           1. 当前只支持DB_CLIENT_TYPE中所列的数据库;
           2. 连接池不再使用时,请使用db_client_destory_pool释放对象;
           3. 此连接池中的连接数量为"一次成型", 即创建连接池时一并把指定的连接数量创建完毕,
              使用过程中,不会根据业务请求量自动添加或者删除连接;
           4. 参数使用介绍:
             +-----------------------+-------------+-------------+-------------+-------------+-------------+-------------+
             |         dbtype        |     host    |     port    |     name    |     user    |    passwd   |   pool_num  |
             +-----------------------+-------------+-------------+-------------+-------------+-------------+-------------+
             | DB_CLIENT_TYPE_DAMO   |     IP地址   |     端口    |     忽略     |     用户名  |    密码      |  最大连接数  |
             +-----------------------+-------------+-------------+-------------+-------------+-------------+-------------+
             | DB_CLIENT_TYPE_MYSQL  |     IP地址   |     端口    |   数据库名称  |     用户名  |    密码      |  最大连接数  |
             +-----------------------+-------------+-------------+-------------+-------------+-------------+-------------+
             | DB_CLIENT_TYPE_SQLITE |    文件全路径 |     忽略    |     忽略     |     忽略    |    忽略      |    忽略     |
             +-----------------------+-------------+-------------+-------------+-------------+-------------+-------------+
             | DB_CLIENT_TYPE_ORACLE |    TNS名称   |     忽略    |     忽略     |     用户名   |   密码      |  最大连接数  |
             +-----------------------+-------------+-------------+-------------+-------------+-------------+-------------+
*/
connection_pool* db_client_create_pool(int dbtype, const char *host, int port, const char *name,
                                            const char *user, const char *passwd, int pool_num);

       db_client_create_pool这个接口是三个接口中的“重中之重”,一切数据库的访问操作,都必须从它开始。

       具体的参数说明和使用介绍,在接口文件中已经写的非常详细了,这里就不再复述了。需要说明的是,由于要兼容不同的数据库访问,不同的数据库访问又需要不同的参数,所以这个接口的参数并不是都有用,需要根据dbtype参数来区别对待,访问何种数据库,请参照说明,匹配不同的参数。

       另外,还需要说明的是,关于连接池这个功能。 这个开发接口实现的连接池是非常简单的连接池,不提供额外的动态关闭和释放连接的功能,也不会根据业务量的变化动态管理这个连接池。你初始化了多少个连接,它就一直帮你管理这些个连接,不会自作主张的替你考虑更多的事情。

       可能你已经看到了,对于sqlite类型,pool_num这个参数是0(其实不光是pool_num,其他参数也被忽略了),它不需要这个参数,因为sqlite就是一个本地文件,它无需连接池。

/*
     功 能:
           释放数据库连接池对象
     参 数:
            pool  :  数据库连接池对象
     返回值:
            返回0(忽略返回值)

     备  注:
            请参考db_client_create_pool接口说明.
*/
int db_client_destory_pool(connection_pool *pool);

        这最后一个接口就无需做过多的介绍了,有分配就有释放,这个是搞C/C++开发的座右铭,如果你不知道这个座右铭,那么你一定不是搞C/C++开发的。

        

       导出函数就介绍到这里了,很简单吧,就三个接口,使用起来是不是很简单,0学习成本?

       有关其他的C++抽象接口,可以直接看接口文件,里面都有详细的说明,而且通过函数的名字也能够一目了然的知道它是干什么的,这里就不介绍了。

       下载链接:点我

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值