自定义的mysql接口类

代码下载地址:https://download.csdn.net/download/f110300641/10780482

本类的特点:

1、创建了连接池

2、利用boost的无锁队列,可以高速异步执行sql,不阻塞程序

3、可以根据字段名获得结果

简单的使用例子如下:

创建表格的sql:

CREATE TABLE `student` (
    `no` INT(11) not NULL COMMENT '学号',
    `name` CHAR(11) NOT NULL DEFAULT '' COMMENT '姓名',
    `birtday` TIMESTAMP(3) not NULL DEFAULT CURRENT_TIMESTAMP(3) comment '生日',
    `entern` datetime NULL DEFAULT null,
    `stature` DOUBLE NULL DEFAULT NULL COMMENT '身高',
    primary key (`no`),
    INDEX `birtday` (`birtday`)
)
COMMENT='学生表'
default charset=utf8
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;

#include <iostream>
#include <mysql.h>
#include <stdio.h>
#include <mysql.h>
#include <string>
#include <time.h>
#include <random>
#include <thread>
#include <chrono>
#include <string.h>
#include "tg_mysql_result.h"
#include"tg_mysql_common.h"
#include"tg_mysql_connpool.h"

void test()
{
    tg_mysql_param param;
    param.host     = "192.168.0.105";
    param.user     = "root";
    param.pwd      = "root";
    param.dbname   = "test";
    param.charset  = "utf8";
    param.time_out  = 5;
    param.pool_size = 10;

    std::string error;
    //创建连接池
    if ( !g_db_pool.create( param, error ) )
    {
        std::cout<<"线程池创建失败,Err=" << error << std::endl;
        return;
    }

    char sql[1024];
    for(int i=0; i<5; i++)
    {
        memset(sql, 0, sizeof (sql));
        if(i%2==0)
        {
            sprintf(sql, "INSERT INTO `student` (`no`, `name`, `birtday`, `entern`, `stature`) \
                VALUES ('%d', '小白%d', '2013-11-12 09:04:58', '2015-11-12 09:05:10.000', '%f');",
                    i+1,i+1,9.5+i);
        }
        else
        {
            sprintf(sql, "INSERT INTO `student` (`no`, `name`, `birtday`, `stature`) \
                VALUES ('%d', '小白%d', '2013-11-12 09:04:58', '%f');",
                    i+1,i+1,9.5+i);
        }

        if ( !g_db_pool.push(sql))
        {
            std::cout << "Err,Failed to ExecuteSql:" << sql << std::endl;
        }
    }

    std::this_thread::sleep_for(std::chrono::seconds(2));

    memset(sql, 0, sizeof (sql));
    sprintf(sql, "select no, name, entern, stature from student;");
    auto results_ptr = g_db_pool.query(sql, error);
    if (results_ptr)
    {
        printf( "The record count=%ld\n", results_ptr->get_row_count() );

        while ( results_ptr->get_next_row() )
        {
            int no = false;
            results_ptr->try_get_value( "no", no, error );

            std::string name;
            results_ptr->try_get_value( "name", name, error );

            std::string entern;
            results_ptr->try_get_value( "entern", entern, error );

            double stature = 0.0;
            results_ptr->try_get_value( "stature", stature, error );

            int errortmp=-900;
            results_ptr->try_get_value( "error", errortmp, error );

            std::cout << no << " ";
            std::cout << name << " ";
            std::cout << entern << " ";
            std::cout << stature << " ";
            std::cout << errortmp << " ";
            std::cout << std::endl;
        }
    }
}

int main()
{
    test();

    return 0;
}
 

具体类定义:

tg_mysql_common.h

#ifndef TG_MYSQL_COMMON_H
#define TG_MYSQL_COMMON_H

#include<string>
#include <mysql.h>

const int CONST_MYSQL_EXEC_FAILED_COUNT   = 3;//最大异步执行失败次数
const int CONST_MYSQL_QUEQUE_CAPACITY     = 3 * 1024;//异步执行队列最大容量

const int CONST_MYSQL_CONN_MIN = 1;//最小连接数
const int CONST_MYSQL_CONN_MAX = 60;//最大连接数

/**
    * @brief
    数据库连接设置结构体
    */
struct tg_mysql_param
{
    ///数据库主机地址
    std::string host;
    ///用户名
    std::string user;
    ///密码
    std::string pwd;
    ///数据库名
    std::string dbname;
    ///字符集
    std::string charset;

    ///连接数据库超时(单位:秒)
    int time_out;
    ///连接池大小
    uint pool_size;
    tg_mysql_param():time_out(0),pool_size(CONST_MYSQL_CONN_MIN)
    {
    }
};

/**
    * @brief
    异步执行结构体
    */
struct tg_async_sql
{
    int failed_count;//执行失败次数
    std::string sql; //SQ语句
    tg_async_sql(std::string sql):failed_count(0),sql(sql)
    {
    }

    tg_async_sql(const tg_async_sql& data)
    {
        failed_count = data.failed_count;
        sql = data.sql;
    }
};

struct tool_mysql_time
{
    ///把时间字符串转成MYSQL_TIME
    static void str2time(const std::string& str, MYSQL_TIME& out_data)
    {
        sscanf( str.c_str(), "%d-%d-%d %d:%d:%d", &out_data.year, &out_data.month, &out_data.day, &out_data.hour, &out_data.minute, &out_data.second );
        out_data.second_part = 0;//microseconds
        out_data.neg = false;
        out_data.time_type = MYSQL_TIMESTAMP_DATE;
    }
    ///把MYSQL_TIME转成时间字符串
    static std::string time2str( const MYSQL_TIME& value)
    {
        char str[25]={0};
        sprintf( str, "%d-%d-%d %02d:%02d:%02d", value.year, value.month, value.day, value.hour, value.minute, value.second );
        return std::string(str);
    }

    static void clear( MYSQL_TIME& value )
    {
        value.year         = 0;
        value.month        = 0;
        value.day          = 0;
        value.hour         = 0;
        value.minute       = 0;
        value.second       = 0;
        value.neg          = false;
        value.second_part  = 0;
        value.time_type    = MYSQL_TIMESTAMP_DATETIME;
    }
};

#endif // TG_MYSQL_COMMON_H

tg_mysql_result.h

#ifndef TG_MYSQL_RESULT_H
#define TG_MYSQL_RESULT_H
#include<mysql.h>
#include<map>
#include<tg_mysql_common.h>
#include<string>
#include<memory>
#include<memory.h>


class tg_mysql_result
{
private:
    ///结果集
    MYSQL_RES* _result_ptr;
    ///当前记录行
    MYSQL_ROW _cur_row_ptr;
    ///字段名和字段下标对应列表(key是字段名,value是字段下标)
    std::map<std::string,int> _name_index_map;
public:
    tg_mysql_result(MYSQL_RES *result_ptr):_result_ptr(result_ptr),_cur_row_ptr(nullptr)
    {
        uint field_cout = mysql_num_fields( _result_ptr );
        for ( uint i = 0; i < field_cout; i++ )
        {
            MYSQL_FIELD *field_ptr = mysql_fetch_field_direct( _result_ptr, i );
            if ( nullptr ==  field_ptr )
            {
                continue;
            }

            _name_index_map.insert( std::make_pair( field_ptr->name, i ) );
        }
    }
    ~tg_mysql_result()
    {
        if ( nullptr == _result_ptr )
        {
            return;
        }

        mysql_free_result( _result_ptr );
        _result_ptr = nullptr;
        _cur_row_ptr = nullptr;
        _name_index_map.clear();
    }

    ///获得下一条记录
    bool get_next_row()
    {
        return  ( _cur_row_ptr = mysql_fetch_row( _result_ptr ) ) != nullptr;
    }

    long get_row_count()
    {
        return static_cast<long>(mysql_num_rows( _result_ptr ));
    }

    bool try_get_value( const char * name, int & out_value, std::string & error )
    {
        char* value_ptr = nullptr;
        bool is_null = false;
        if ( !_try_get_value( name, value_ptr, is_null, error ) )
        {
            return false;
        }

        out_value = is_null ? 0 : std::stoi(value_ptr);

        return true;
    }

    bool try_get_value( const char * name, long long & out_value, std::string & error )
    {
        char* value_ptr = nullptr;
        bool is_null = false;
        if ( !_try_get_value( name, value_ptr, is_null, error ) )
        {
            return false;
        }

        out_value = is_null ? 0 : std::stoll(value_ptr);

        return true;
    }

    bool try_get_value( const char * name, std::string & out_value, std::string & error )
    {
        char* value_ptr = nullptr;
        bool is_null = false;
        if ( !_try_get_value( name, value_ptr, is_null, error ) )
        {
            return false;
        }

        out_value = is_null ? "" : value_ptr;

        return true;
    }

    bool try_get_value( const char * name, char * out_value, uint length, std::string & error )
    {
        char* value_ptr = nullptr;
        bool is_null = false;
        if ( !_try_get_value( name, value_ptr, is_null, error ) )
        {
            return false;
        }

        is_null ? memset( out_value, 0, length ) : strncpy( out_value, value_ptr, length );

        return true;
    }

    bool try_get_value( const char * name, bool & out_value, std::string & error )
    {
        char* value_ptr = nullptr;
        bool is_null = false;
        if ( !_try_get_value( name, value_ptr, is_null, error ) )
        {
            return false;
        }

        out_value = is_null ? false : std::stoi(value_ptr);

        return true;
    }

    bool try_get_value( const char * name, float & out_value, std::string & error )
    {
        char* value_ptr = nullptr;
        bool is_null = false;
        if ( !_try_get_value( name, value_ptr, is_null, error ) )
        {
            return false;
        }

        out_value = is_null ? 0 : std::stof(value_ptr);

        return true;
    }

    bool try_get_value( const char * name, double & out_value, std::string & error )
    {
        char* value_ptr = nullptr;
        bool is_null = false;
        if ( !_try_get_value( name, value_ptr, is_null, error ) )
        {
            return false;
        }

        out_value = is_null ? 0 : std::stod(value_ptr);

        return true;
    }

private:
    ///获得原始字符串值
    bool _try_get_value( const char * name, char*& out_ptr, bool& is_null, std::string& error )
    {
        is_null = false;
        int index = -1;
        auto key_value = _name_index_map.find( name );
        if ( _name_index_map.end() != key_value )
        {
            index = key_value->second;
        }
        else
        {
            error = "Error,can't find field name: ";
            error += name;
            return false;
        }

        out_ptr = _cur_row_ptr[index];
        if ( nullptr == out_ptr || 0 == out_ptr[0])
        {
            is_null = true;
        }

        return true;
    }
};

#endif // TG_MYSQL_RESULT_H
 

tg_mysql_connect.h

#ifndef TG_MYSQL_CONNECT_H
#define TG_MYSQL_CONNECT_H
#include<mysql.h>
#include<string>
#include<memory>
#include<string.h>
#include"tg_mysql_common.h"
#include"tg_mysql_result.h"

class tg_mysql_connect
{
private:
    MYSQL * _conn_ptr;//数据库连接
    bool _is_temp;//是否是临时的(如果是临时使用的,归还到连接池中时会自动删除,以保持总体连接数不变)

    tg_mysql_param _param;
public:
    uint fail_conn_count;
    tg_mysql_connect(const tg_mysql_param& param, bool is_temp = false ):
        _conn_ptr(nullptr),_is_temp(is_temp),_param(param),fail_conn_count(0)
    {
    }
    ~tg_mysql_connect()
    {
        _close();
    }

    ///连接数据库
    bool connect(std::string & error )
    {
        _close();
        //创建
        _conn_ptr = mysql_init( nullptr );

        //超时设置
        if ( mysql_options( _conn_ptr, MYSQL_OPT_CONNECT_TIMEOUT, &(_param.time_out) ) != 0
             ||mysql_set_character_set( _conn_ptr, _param.charset.c_str() ) != 0
             ||!mysql_real_connect( _conn_ptr, _param.host.c_str(), _param.user.c_str(), _param.pwd.c_str(), _param.dbname.c_str(), 0, nullptr, 0 )
             )
        {
            error = get_last_error();
            return false;
        }

        return true;
    }

    ///测试连接
    bool ping( std::string& error )
    {
        if (mysql_ping( _conn_ptr ) != 0 )
        {
            error = get_last_error();
            return false;
        }

        return true;
    }
    ///设置自动提交
    bool autocommit( bool is_auto, std::string& error )
    {
        if(!mysql_autocommit( _conn_ptr, is_auto ))
        {
            error = get_last_error();
            return false;
        }

        return true;
    }
    ///提交
    bool commit( std::string& error )
    {
        if(!mysql_commit( _conn_ptr ))
        {
            error = get_last_error();
            return false;
        }

        return true;
    }

    bool rollback( std::string& error )
    {
        if(!mysql_rollback( _conn_ptr ))
        {
            error = get_last_error();
            return false;
        }

        return true;
    }

    std::shared_ptr<tg_mysql_result> executequery( const char * sql, std::string& error )
    {
        if (mysql_query( _conn_ptr, sql ) != 0 )
        {
            error = get_last_error();
            return nullptr;
        }

        auto ptr = mysql_store_result( _conn_ptr );
        if(ptr)
        {
            return std::make_shared<tg_mysql_result>(ptr);
        }

        error = get_last_error();
        return nullptr;
    }

    //返回-1 失败
    long executesql( const char * sql, std::string& error )
    {
        long tmp=0;
        if (mysql_query( _conn_ptr, sql ) != 0  || (tmp=static_cast<long>(mysql_affected_rows( _conn_ptr ))) == -1)
        {
            error = get_last_error();
        }

        return tmp;
    }

    //返回-1 失败
    long executerealsql( const char * sql, std::string& error )
    {
        auto len = strlen( sql );
        long tmp=-1;
        if (mysql_real_query( _conn_ptr, sql, len ) != 0  || (tmp=static_cast<long>(mysql_affected_rows( _conn_ptr ))) == -1)
        {
            error = get_last_error();
        }

        return tmp;
    }

    ///获得最后一次错误信息
    const std::string get_last_error()
    {
        if ( nullptr == _conn_ptr )
        {
            return "Error,not connected to database!";
        }

        return std::string(mysql_error( _conn_ptr ));
    }

    ///获得最后一次插入的ID
    long get_last_insert_id( std::string& error )
    {
        if ( nullptr == _conn_ptr )
        {
            error = "Error,not connected to database!";
            return -1;
        }

        return static_cast<long>(mysql_insert_id( _conn_ptr  ));
    }

    ///是否是临时的连接
    bool is_temp()
    {
        return _is_temp;
    }

    void _close()
    {
        if ( _conn_ptr )
        {
            mysql_close( _conn_ptr );
            _conn_ptr = nullptr;
        }
    }
};

#endif // TG_MYSQL_CONNECT_H
 

tg_mysql_connpool.h

#ifndef TG_MYSQL_CONNPOOL_H
#define TG_MYSQL_CONNPOOL_H

#include <boost/bind.hpp>
#include<boost/lockfree/queue.hpp>
#include<boost/chrono.hpp>
#include<mutex>
#include<list>
#include<boost/atomic.hpp>
#include<boost/serialization/singleton.hpp>
#include<boost/thread.hpp>
#include"tg_mysql_common.h"
#include"tg_mysql_connect.h"
#include"tg_mysql_result.h"
#include<memory>
#include<iostream>

class tg_mysql_connpool
{
private:
    ///正在使用的数据库连接
    std::list<std::shared_ptr<tg_mysql_connect>> _busy_list;
    ///没有使用的数据库连接
    std::list<std::shared_ptr<tg_mysql_connect>> _idl_list;
    ///数据库连接参数
    tg_mysql_param _param;
    std::mutex _mutex;

    boost::thread _thread_hand;

    ///异步执行线程用的数据库连接
    std::shared_ptr<tg_mysql_connect> _ansynconn;

    ///异步执行无锁队列
    boost::lockfree::queue<tg_async_sql*, boost::lockfree::capacity<CONST_MYSQL_QUEQUE_CAPACITY>> _queue;

public:
    tg_mysql_connpool():_ansynconn(nullptr)
    {
    }
    ~tg_mysql_connpool()
    {
        _free();
    }

    ///创建数据库连接池
    bool create(const tg_mysql_param& param, std::string& error )
    {
         _free();

        std::unique_lock<std::mutex> lock( _mutex );

        _param = param;
        _deal_pool_size(_param.pool_size);

        for ( uint i = 0; i < _param.pool_size; i++ )
        {
            auto ptr = std::make_shared<tg_mysql_connect>(_param);
            if ( !ptr->connect( error ) )
            {
                return false;
            }

            _idl_list.push_back( ptr );
        }

        //创建异步执行线程
        auto ptr = std::make_shared<tg_mysql_connect>(_param);
        if ( !ptr->connect( error ) )
        {
            return false;
        }
        _ansynconn = ptr;

        //启动异步执行线程
        _thread_hand = boost::thread( &tg_mysql_connpool::_thread_proc, this );

        return true;
    }

    ///把SQL语句加入异步执行队列
    bool push( const std::string& sql )
    {
        tg_async_sql* ptr = new tg_async_sql(sql);
        if(_queue.push(ptr))
        {
            return true;
        }

        _delete(ptr);
        return false;
    }

    std::shared_ptr<tg_mysql_result> query( const char *sql, std::string& error )
    {
        auto ptr = get_connect( error );
        if ( !ptr )
        {
            return nullptr;
        }

        auto result_ptr = ptr->executequery( sql, error );
        give_back(ptr);

        return result_ptr;
    }

    ///失败返回-1
    long executesql( const char *sql, std::string& error )
    {
        auto ptr = get_connect( error );
        if ( !ptr )
        {
            return false;
        }

        auto tmp = ptr->executesql( sql, error );
        give_back(ptr);
        return tmp;
    }

    ///从连接池中获得一个连接
    std::shared_ptr<tg_mysql_connect> get_connect( std::string& error )
    {
        std::unique_lock<std::mutex> lock( _mutex );

        std::shared_ptr<tg_mysql_connect> ptr = nullptr;
        if ( _idl_list.size() > 0 )
        {
            ptr = *(_idl_list.begin());
            _idl_list.pop_front();
            _busy_list.push_back( ptr );
        }
        else
        {
            if ( _busy_list.size() < CONST_MYSQL_CONN_MAX )
            {
                auto ptr = std::make_shared<tg_mysql_connect>(_param, true);
                if ( !ptr->connect( error ) )
                {
                    error = "Error,failed connect to database!";
                    return nullptr;
                }

                _busy_list.push_back( ptr );
            }
            else
            {
                error = "Error,db connect count beyond the max connect count!";
                return nullptr;
            }
        }

        return ptr;
    }
    ///归还连接到连接池
    void give_back( std::shared_ptr<tg_mysql_connect>& ptr )
    {
        std::unique_lock<std::mutex> lock( _mutex );
        _busy_list.remove( ptr );

        //如果是临时连接,不再放入到空闲连接列表中
        if ( !ptr->is_temp() )
        {
            _idl_list.push_back( ptr );
        }
    }

private:
    void _delete(tg_async_sql*& data_ptr)
    {
        if (data_ptr)
        {
            delete data_ptr;
            data_ptr = nullptr;
        }
    }

    void _thread_proc()
    {
        try
        {
            std::string error;
            while( true )
            {
                tg_async_sql* sql_ptr(nullptr);
                while (_queue.pop( sql_ptr )  && sql_ptr)
                {
                    //std::cout<<"执行: " << sql_ptr->sql.c_str()<<std::endl;
                    _thread_proc_sub(sql_ptr,error);

                    _delete(sql_ptr);
                }

                boost::this_thread::sleep_for( boost::chrono::milliseconds( 10 ) );
            }
        }
        catch (boost::thread_interrupted&)
        {
        }
    }

    void _thread_proc_sub(tg_async_sql*& sql_ptr, std::string& error)
    {
        if ( !_ansynconn->executerealsql( sql_ptr->sql.c_str(), error ))//失败
        {
            //std::cout<<"失败: " << sql_ptr->sql.c_str()<<std::endl;
            //如果失败了看是不是数据库断开连接了,尝试重新连接一次
            if ( !_ansynconn->ping( error ) && !_ansynconn->connect( error ))
            {
                if(_ansynconn->fail_conn_count++<CONST_MYSQL_EXEC_FAILED_COUNT)
                {
                    //如果连接失败了休息一下
                    boost::this_thread::sleep_for( boost::chrono::milliseconds( 100 ) );
                }
                else
                {
                    throw error;
                }

            }
            else
            {
                _ansynconn->fail_conn_count=0;
            }

            sql_ptr->failed_count++;
            if ( sql_ptr->failed_count < CONST_MYSQL_EXEC_FAILED_COUNT )
            {
                auto ptr = new tg_async_sql(*sql_ptr);
                _queue.push( ptr );
            }
        }
    }

    static void _deal_pool_size(uint& size)
    {
        size = (size < CONST_MYSQL_CONN_MIN) ? CONST_MYSQL_CONN_MIN : size;
        size = (size > CONST_MYSQL_CONN_MAX) ? CONST_MYSQL_CONN_MAX : size;
    }

    void _free()
    {
        //停止异步执行线程
        if(_thread_hand.joinable())
        {
            _thread_hand.interrupt();
        }

        //把异步执行无锁队列中每个元素释放
        tg_async_sql* data_ptr(nullptr);
        while ( _queue.pop( data_ptr ) )
        {
            _delete (data_ptr);
        }

        _ansynconn=nullptr;
        std::unique_lock<std::mutex> lock( _mutex );
        _busy_list.clear();
        _idl_list.clear();
    }
};

//单件相关定义
typedef boost::serialization::singleton<tg_mysql_connpool> singleton_pool;
#define g_db_pool singleton_pool::get_mutable_instance()
#define g_db_pool_const singleton_pool::get_const_instance()

#endif // TG_MYSQL_CONNPOOL_H
 

猜你喜欢

转载自blog.csdn.net/f110300641/article/details/83997241
今日推荐