代码下载地址:https://download.youkuaiyun.com/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