c++ mysql数据库操作api接口的封装

   日期:2020-05-07     浏览:115    评论:0    
核心提示:c++ mysql数据库接口的封装主要涉及预处理接口数据库

目录

    • 一:关键接口说明
    • 二:具体实现
    • 三:接口测试
    • 四:后续

一:关键接口说明

一般预处理流程都是,连接数据库–>预处理–>绑定查询参数–>执行查询–>获取查询结果
故api封装之后有如下几个关键的接口:

1:bool connect(); //连接数据库,初始化数据库连接等
2:bool prepare(const std::string &query);//预处理
3:template<typename T> void bindValue(int pos, const T &value);//给placeholder相对应的位置绑定参数
4:bool execute();//执行数据库查询
5:bool next();//移到下一条记录
6:template<typename T>T value(int index);//获取结果集index位置中T类型的结果

二:具体实现

1:首先需要封装数据库连接的参数配置

DatabaseOption.hpp

#include <string>

struct DatabaseOption {
    std::string host = "127.0.0.1";//数据库ip地址
    int port = 3307;//端口号
    std::string username = "root";//用户名
    std::string password = "123456";//数据库密码
    std::string databaseName = "test";//数据库名
    int connectTimeout = 0;//连接的超时时间
    std::string charsetName = "utf8";//编码
    int reconnectTime = 1;//超时重连次数
};

2:然后需要封装预处理的参数绑定

PrepareBinder.hpp


#include <vector>
#include <string>
#include <algorithm>
#include <mysql.h>
#include <iostream>


class PrepareBinder {
private:
    std::vector<MYSQL_BIND> paramBinds;//预处理的参数绑定
public:

    
    explicit PrepareBinder(int prepareBindNum) {
        paramBinds.resize(prepareBindNum);//初始化绑定参数列表
    }

    std::vector<MYSQL_BIND> &getParamBinds() {
        return paramBinds;
    }

    
    void bindValue(int pos, const int &value) {
        paramBinds[pos].buffer_type = MYSQL_TYPE_LONG;
        paramBinds[pos].buffer = (void *) &value;
        paramBinds[pos].is_unsigned = false;
    }

    
    void bindValue(int pos, const unsigned int &value) {
        paramBinds[pos].buffer_type = MYSQL_TYPE_LONG;
        paramBinds[pos].buffer = (void *) &value;
        paramBinds[pos].is_unsigned = true;
    }

    
    void bindValue(int pos, const std::string &value) {
        paramBinds[pos].buffer_type = MYSQL_TYPE_STRING;
        paramBinds[pos].buffer = (void *) value.c_str();
        paramBinds[pos].buffer_length = value.size();
    }
};

3:再有需要对封装查询结果集进行封装

ResultBinder.hpp



#include <vector>
#include <map>
#include <mysql.h>
#include <functional>
#include <iostream>


class ResultBinder {
private:
    
    template<typename T>
    struct IndexWrapper {
        int index = 0;//索引

        explicit IndexWrapper(int index) : index(index) {}
    };

private:
    const static int STRING_MAX_LENGTH = 65535;

    std::vector<MYSQL_BIND> resultBinds;

    //字符串缓存
    std::vector<std::vector<char>> stringBuffer;
    //整型的缓存
    std::vector<int> intBuffer;

    //类型与处理函数映射
    std::map<int, std::function<void(int)>> typeProcessMap = {
            {MYSQL_TYPE_LONG,       std::bind(&ResultBinder::bindInt, this, std::placeholders::_1)},
            {MYSQL_TYPE_VAR_STRING, std::bind(&ResultBinder::bindString, this, std::placeholders::_1)}
    };
private:
    void bindInt(int index) {
        resultBinds[index].buffer_type = MYSQL_TYPE_LONG;
        resultBinds[index].buffer = &intBuffer[index];
    }

    void bindString(int index) {
        stringBuffer[index].clear();
        stringBuffer[index].resize(STRING_MAX_LENGTH);
        resultBinds[index].buffer_type = MYSQL_TYPE_STRING;
        resultBinds[index].buffer = stringBuffer[index].data();
        resultBinds[index].buffer_length = STRING_MAX_LENGTH;
    }

    
    std::string value(IndexWrapper<std::string> wrapper) {
        return stringBuffer[wrapper.index].data();
    }

    
    int value(IndexWrapper<int> wrapper) {
        return intBuffer[wrapper.index];
    }

public:

    
    explicit ResultBinder(int resultBindNum) {
        resultBinds.resize(resultBindNum);
        stringBuffer.resize(resultBindNum);
        intBuffer.resize(resultBindNum);
    }


    
    void bindValue(enum_field_types fieldTypes, int index) {
        if (typeProcessMap.find(fieldTypes) == typeProcessMap.end()) {
            std::cerr << "[unsupported type]" << fieldTypes << std::endl;
            return;
        }
        //调用绑定函数
        typeProcessMap[fieldTypes](index);
    }

    
    template<typename T>
    T value(int index) {
        return value(std::move(IndexWrapper<T>(index)));
    }

    std::vector<MYSQL_BIND> &getBindResult() {
        return resultBinds;
    }
};

4:最后是对mysql查询接口的封装

Connection.hpp


#include "DatabaseOption.hpp"
#include "PrepareBinder.hpp"
#include "ResultBinder.hpp"
#include <mysql.h>
#include <memory>
#include <vector>
#include <iostream>
#include <list>


class Connection {
public:
    
    void setOption(const DatabaseOption &option) {
        this->option = option;
    }

    
    void close() {
        if (connection != nullptr) {
            mysql_close(connection);
            connection = nullptr;
        }
        if (!mysqlStmt)
            mysql_stmt_free_result(mysqlStmt);
    }

    
    bool ping() {
        return mysql_ping(connection) == 0;
    }

    
    int getLastAffectedRows() {
        return (int) mysql_affected_rows(connection);
    }

    
    bool connect() {
        //初始化mysql
        connection = mysql_init(nullptr);
        if (nullptr == connection) {
            setLastError("mysql init failed");
            return false;
        }
        //设置超时时间
        if (option.connectTimeout > 0) {
            if (0 != mysql_options(connection, MYSQL_OPT_CONNECT_TIMEOUT, &option.connectTimeout)) {
                setLastError("set option error");
                return false;
            }
        }
        //编码
        mysql_options(connection, MYSQL_SET_CHARSET_NAME, option.charsetName.c_str());
        mysql_options(connection, MYSQL_OPT_RECONNECT, &option.reconnectTime);
        if (!mysql_real_connect(connection, option.host.c_str(), option.username.c_str(), option.password.c_str(),
                                option.databaseName.c_str(), option.port, nullptr, 0)) {
            setLastError("failed to connect to database");
            return false;
        }
        return true;
    }


    void setLastError(const std::string &lastError) {
        this->lastError = "[" + lastError + "] " + mysql_error(connection);
        std::cerr << this->lastError << std::endl;
    }

    std::string getLastError() const {
        return this->lastError;
    }

    
    bool begin() {
        if (mysql_query(connection, "BEGIN")) {
            setLastError("begin error");
            return false;
        }
        return true;
    }

    
    bool commit() {
        if (mysql_query(connection, "COMMIT")) {
            setLastError("commit error");
            return false;
        }
        return true;
    }

    
    bool rollback() {
        if (mysql_query(connection, "ROLLBACK")) {
            setLastError("rollback error");
            return false;
        }
        return true;
    }

    
    bool execute() {

        //绑定查询参数
        if (mysql_stmt_bind_param(mysqlStmt, &prepareBinder->getParamBinds()[0])) {
            setLastError("mysql_stmt_bind_param error");
            return false;
        }

        //获取结果集元数据
        mysqlRes = mysql_stmt_result_metadata(mysqlStmt);
        auto columnNum = mysql_num_fields(mysqlRes);
        resultBinder = std::make_shared<ResultBinder>(columnNum);
        //根据表元数据绑定结果集
        for (int i = 0; i < mysqlRes->field_count; i++) {
            resultBinder->bindValue(mysqlRes->fields[i].type, i);
// std::cout << "name:" << mysqlRes->fields[i].name << " type: " << mysqlRes->fields[i].type << std::endl;
        }
        //绑定查询结果
        if (mysql_stmt_bind_result(mysqlStmt, &resultBinder->getBindResult()[0])) {
            setLastError("mysql_stmt_bind_result");
            return false;
        }

        if (mysql_stmt_execute(mysqlStmt)) {
            setLastError("mysql_stmt_execute error");
            return false;
        }
        return true;
    }


    
    template<typename T>
    void bindValue(int pos, const T &value) {
        prepareBinder->bindValue(pos, value);
    }

    
    bool prepare(const std::string &query) {
        //初始化预处理环境
        mysqlStmt = mysql_stmt_init(connection);
        if (!mysqlStmt) {
            setLastError("mysql_stmt_init error");
            return false;
        }
        if (mysql_stmt_prepare(mysqlStmt, query.c_str(), query.size())) {
            setLastError("mysql_stmt_prepare error");
            return false;
        }
        //获取预处理绑定的参数个数
        auto paramCount = mysql_stmt_param_count(mysqlStmt);
        prepareBinder = std::make_shared<PrepareBinder>(paramCount);
        return true;
    }

    
    bool next() {
        //0表示正确,其他情况返回错误
        return mysql_stmt_fetch(mysqlStmt) == 0;
    }

    
    template<typename T>
    T value(int index) {
        return resultBinder->value<T>(index);
    }

private:
    MYSQL *connection = nullptr;
    MYSQL_STMT *mysqlStmt = nullptr;
    MYSQL_RES *mysqlRes = nullptr;//结果

    std::string lastError;//最后的错误信息
    DatabaseOption option;//数据库配置信息

    std::shared_ptr<PrepareBinder> prepareBinder = nullptr;
    std::shared_ptr<ResultBinder> resultBinder = nullptr;

};

三:接口测试

1:数据库的准备

mysql> create database test;
mysql> use test;
mysql> select * from user;
mysql> insert into user(id,name)values(1,"zhangsan"),(2,"lisi"),(3,"wangwu"),(4,"liwu");
mysql> select * from user;
+------+----------+
| id   | name     |
+------+----------+
|    1 | zhangsan |
|    2 | lisi     |
|    3 | wangwu   |
|    4 | liwu     |
+------+----------+

2:测试代码

main.cpp

#include <Connection.hpp>

int main() {

    Connection connection;
    connection.setOption(DatabaseOption());//初始化配置
    connection.connect();//连接数据库
    std::string sql = "select name,id from user where `id` > ? and `name` like ?";
    connection.prepare(sql);//预处理
    connection.bindValue(0, 1);//绑定查询参数
    connection.bindValue(1, "%wu");
    connection.execute();//执行查询
    while (connection.next()) {
    	//获取结果
        std::cout << "id = " << connection.value<int>(1);
        std::cout << " name = " << connection.value<std::string>(0) << std::endl;
    }

    return 0;
}

输出结果如下

id = 3 name = wangwu
id = 4 name = liwu

四:后续

后续加入数据库连接池

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服