c++ 基於Mysql原生庫二次封裝的輕量級庫

一 、前言

       在C++項目中經常要使用Mysql數據庫,在QT項目中使用Mysql還需要 Mysql驅動,但是在QT4.7,4.8版本中,mysql驅動需要自己編譯,在編譯過程中會遇到很多問題,需要花很多時間來解決,所以我們要想別的辦法;一是,不直接使用mysql驅動來操作mysql數據庫,可以使用odbc的方式來操作數據庫,並且使用ODBC操作數據之前需要配置ODBC源;二是,可以繞開QT的數據庫框架,直接使用mysql原生的庫來操作mysql;所以我們基於原生的庫進行了二次封裝。

二、源代碼

頭文件.h

#ifndef DATABASE_MYSQL_H
#define DATABASE_MYSQL_H
#include <string>
#include <vector>

#include "database_mysql_global.h"

class database_mysql_t;
//批量插入數據
class DATABASE_MYSQL_EXPORT batch_insert_adapter_t
{
public:
	batch_insert_adapter_t(database_mysql_t *database, int buffer_size = 1000000, int flush_row = 50000);
	~batch_insert_adapter_t();
	void begin_add_field(const char * csz_table);                       //開始插入字段
	void add_field(const char *csz_field);         //添加字段 
	void end_add_field();                          //結束插入字段
	void begin_add_row();                          //開始插入數值
	void add_value(char value);
	void add_value(int value);
	void add_value(unsigned int value);	
	void add_value(long value);
	void add_value(unsigned long value);
	void add_value(float value);
	void add_value(double value);
	void add_value(std::string value);
	void add_value(const char * value);
	void add_value(long long value);
	void add_value(unsigned long long value);
	void add_value(void * value, int n_length);
	bool end_add_row();                           //結束添加值
	bool flush();                                 //將數據插入數據庫
	int get_sum_row();                            //獲取總的行數
private:
	std::string m_str_table;                      //表格名稱
	std::vector<std::string> m_v_field_names;     //需要插入的字段名稱	
	int  m_n_field;                               //字段個數
	int  m_n_field_added;                         //已經添加的字段數
	database_mysql_t *m_database;
	int  m_buffer_size;
	int  m_flush_row;
	char *m_data_buffer;       //數據緩存
	char * m_p_data;                              //數據緩存當前的位置
	char * m_p_data_start;                        //數據開始位置   
	char * m_p_row_start;                         //行的起始地址
	int    m_n_row_num;                           //行數
	int    m_n_row_max_length;                    //行長度
	int    m_n_sum_row;        
};
//MYSQL返回的行定義
typedef  char** row_t;    
//返回結果集
class DATABASE_MYSQL_EXPORT res_t     //爲select的返回結果
{
	friend class database_mysql_t;
public:
	int  row_num();                 //獲取結果集的行數
	int  field_num();               //獲取字段個數
	unsigned long * field_lengths();//獲取當前行的各個字段長度	
	row_t get_next_row();           //獲取下一行數據
	row_t get_row(int n_offset);    //獲取指定偏移的數據
	row_t operator[](int n_offset); //獲取第幾行
	inline void erase();            //清空本結果集

	res_t();	
	res_t(void *res);
	res_t(res_t& res);              //拷貝構造函數
	res_t& operator=(res_t& res);   //賦值
	operator bool(void);            //判斷結果集是否返回成功
	~res_t();
private:	
	void * m_data;             //數據
};
//數據庫適配類
class DATABASE_MYSQL_EXPORT database_mysql_t
{
public:
	database_mysql_t(void);
	virtual ~database_mysql_t(void);
	bool connet(const char *csz_host, const char *csz_user, const char *csz_password, const char *csz_db=0, const unsigned int un_port = 3306);   //連接數據庫
	void dis_connect();                                    //斷開連接
	bool use_db(const char *csz_db);                       //切換數據庫
	bool set_char_set(const char * csz_char_set);          //設置字符集

	bool has_db(const char * csz_db);                      //數據庫是否存在
	bool create_db(const char * csz_db);                   //創建數據庫,輸入爲數據庫的名稱
	bool drop_db(const char * csz_db);                     //刪除數據庫,輸入爲數據庫的名稱
	bool has_table(const char * csz_table);                //該表格是否存在
	bool create_table(const char *csz_sql);                //創建表,輸入爲創建表的sql語句
	bool drop_table(const char * csz_talbe);               //刪除表,輸入爲表的名稱

	res_t select(const char * csz_sql);                    //查詢
	int  insert(const char * csz_sql, int n_length = 0);   //插入
	int  update(const char * csz_sql, int n_length = 0);   //更新
	int  remove(const char * csz_sql);                     //刪除
	int  get_affected_rows();                              //獲取受到影響的行
	bool autocommit(bool bflag);                           //不允許自動事務處理
	bool commit();                                         //執行事務
	bool rollback();                                       //事務回滾
	bool query(const char * csz_data, int n_length = 0);   //查詢,返回受影響的行數

	const char * get_error();                              //返回數據庫操作的錯誤信息
	unsigned int get_errno();                              //返回數據庫操作錯誤代碼 非錯誤返回0
private:
	void * m_mysql;                //mysql連接句柄
};

#endif // DATABASE_MYSQL_H

源文件.cpp

#include "stdafx.h"
#include "database_mysql.h"

#define __LCC__
#include <mysql.h>

//批量插入適配器
batch_insert_adapter_t::batch_insert_adapter_t( database_mysql_t *database, int buffer_size/* = 1000000*/, int flush_row/* = 50000*/)
	: m_database(database), m_n_field(0), m_n_field_added(0), m_p_data(0), m_p_data_start(0),m_n_row_num(0), m_n_row_max_length(0),m_p_row_start(0),m_n_sum_row(0),m_buffer_size(buffer_size),m_flush_row(flush_row)
{
	m_data_buffer = new char[buffer_size];
	memset(m_data_buffer, 0, m_buffer_size);
}

batch_insert_adapter_t::~batch_insert_adapter_t()
{
	delete[] m_data_buffer;
}

void batch_insert_adapter_t::begin_add_field(const char * csz_table)
{
	m_str_table = csz_table;
	m_v_field_names.clear();      //將以往的字段名刪除
	m_p_data = m_data_buffer;
	m_n_field = 0;
	m_n_field_added = 0;
	m_p_data_start = 0;
	m_n_row_num = 0;
	m_n_row_max_length = 0;
	m_n_sum_row = 0;
}

void batch_insert_adapter_t::add_field( const char *csz_field )
{
	m_v_field_names.push_back(csz_field);
}

void batch_insert_adapter_t::end_add_field()
{
	int pos = sprintf(m_p_data, "insert into %s(", m_str_table.c_str()); 
	m_p_data += pos;
	for (std::vector<std::string>::iterator iter = m_v_field_names.begin(), iter_end = m_v_field_names.end(); iter != iter_end; ++iter)
	{
		pos = sprintf(m_p_data, "%s,", (*iter).c_str());
		m_p_data += pos;
	}
	--m_p_data;
	pos = sprintf(m_p_data, ") values ");
	m_p_data += pos;
	m_p_data_start = m_p_data;           //記錄數據開始位置
	m_n_field = (int)m_v_field_names.size();  //獲取字段個數
}

void batch_insert_adapter_t::begin_add_row()
{
	m_p_row_start = m_p_data;                      //行的起始地址
	m_n_field_added = 0;
	int pos = sprintf(m_p_data, "(");
	m_p_data += pos;
}

void batch_insert_adapter_t::add_value(char value )
{
	int pos = sprintf(m_p_data, "\'%c\',", value);
	m_p_data += pos;
	++m_n_field_added;
}

void batch_insert_adapter_t::add_value(int value )
{
	int pos = sprintf(m_p_data, "\'%d\',", value);
	m_p_data += pos;
	++m_n_field_added;
}

void batch_insert_adapter_t::add_value(unsigned int value )
{
	int pos = sprintf(m_p_data, "\'%u\',", value);
	m_p_data += pos;
	++m_n_field_added;
}

void batch_insert_adapter_t::add_value(long value )
{
	int pos = sprintf(m_p_data, "\'%d\',", value);
	m_p_data += pos;
	++m_n_field_added;
}

void batch_insert_adapter_t::add_value(unsigned long value )
{
	int pos = sprintf(m_p_data, "\'%u\',", value);
	m_p_data += pos;
	++m_n_field_added;
}

void batch_insert_adapter_t::add_value(float value )
{
	int pos = sprintf(m_p_data, "\'%f\',", value);
	m_p_data += pos;
	++m_n_field_added;
}

void batch_insert_adapter_t::add_value(double value )
{
	int pos = sprintf(m_p_data, "\'%f\',", value);
	m_p_data += pos;
	++m_n_field_added;
}

void batch_insert_adapter_t::add_value(std::string value )
{
	int pos = sprintf(m_p_data, "\'%s\',", value.c_str());
	m_p_data += pos;
	++m_n_field_added;
}

void batch_insert_adapter_t::add_value(const char * value )
{
	int pos = sprintf(m_p_data, "\'%s\',", value);
	m_p_data += pos;
	++m_n_field_added;
}
void batch_insert_adapter_t::add_value(long long value)
{
	int pos = sprintf(m_p_data, "\'%lld\',", value);
	m_p_data += pos;
	++m_n_field_added;
}
void batch_insert_adapter_t::add_value(unsigned long long value)
{
	int pos = sprintf(m_p_data, "\'%llu\',", value);
	m_p_data += pos;
	++m_n_field_added;
}
void batch_insert_adapter_t::add_value(void * value, int n_length )
{
	*m_p_data = '\'';      //用單引號將要插入的值引住
	++m_p_data;
	memcpy(m_p_data, value, n_length);
	m_p_data += n_length;
	*m_p_data = '\'';
	++m_p_data;
	*m_p_data = ',';          //在字段後面添加','
	++m_p_data;
	++m_n_field_added;
}

bool batch_insert_adapter_t::end_add_row()
{
	if (m_n_field_added != m_n_field)
	{
		//log_t::instance().log("字段值添加錯誤");
		return false;
	}
	*(m_p_data-1) = ')';             //最後一個字段值取出','添加')'
	*m_p_data = ',';                 //添加行間隔','
	++m_p_data;
	++m_n_row_num;                   //行數
	int n_row_length = (int)(m_p_data - m_p_row_start);
	m_n_row_max_length = (m_n_row_max_length > n_row_length) ? m_n_row_max_length : n_row_length;
	if (m_n_row_num > m_flush_row || m_p_data - m_data_buffer + m_n_row_max_length + 100 > m_buffer_size)
	{
		return flush();
	}
	else
		return true;
}

bool batch_insert_adapter_t::flush()
{
	if (m_n_row_num != 0)
	{	
		*(m_p_data-1) = '\0';
		int n_length = (int)(m_p_data - m_data_buffer);
		m_p_data = m_p_data_start;

		if (!m_database->query(m_data_buffer, n_length))
		{
			const char *p = m_database->get_error();
			return false;
		}
		int num = m_database->get_affected_rows();
		if (num != m_n_row_num)
		{
			return false;
		}
		m_n_sum_row += num;
		m_n_row_num = 0;
	}
	return true;
}
int batch_insert_adapter_t::get_sum_row()                            //獲取總的行數
{
	return m_n_sum_row;
}

//數據庫接口
database_mysql_t::database_mysql_t(void) : m_mysql(0)
{
}


database_mysql_t::~database_mysql_t(void)
{
	if (m_mysql != 0)
	{
		dis_connect();
	}
}

bool database_mysql_t::connet( const char *csz_host, const char *csz_user, const char *csz_password, const char *csz_db, const unsigned int un_port /*= 3306*/ )
{
	m_mysql = mysql_init((MYSQL *)m_mysql);
	if (m_mysql == 0)
	{
		return false;
	}
	if (mysql_real_connect((MYSQL *)m_mysql, csz_host, csz_user, csz_password, csz_db, un_port, 0, 0)==0)
	{
		return false;
	}
	return true;
}

void database_mysql_t::dis_connect()
{
	mysql_close((MYSQL *)m_mysql);
	m_mysql = 0;
}

bool database_mysql_t::use_db( const char *csz_db )
{
	char sz_temp[50] = {0};
	sprintf(sz_temp, "use %s", csz_db);
	return query(sz_temp);
}

bool database_mysql_t::set_char_set( const char * csz_char_set )
{
	char sz_temp[50] = {0};
	sprintf(sz_temp, "set names %s", csz_char_set);
	return query(sz_temp);
}

res_t database_mysql_t::select( const char * csz_sql )
{
	if (!query(csz_sql))
	{
		return 0;
	}
	res_t res(mysql_store_result((MYSQL *)m_mysql));
	return res;
}

int database_mysql_t::insert( const char * csz_sql, int n_length /*= 0*/ )
{
	if (!query(csz_sql, n_length))
	{
		return -1;
	}
	return get_affected_rows();
}

int database_mysql_t::update( const char * csz_sql, int n_length /*= 0*/ )
{
	if (!query(csz_sql, n_length))
	{
		return -1;
	}
	return get_affected_rows();
}

int database_mysql_t::remove( const char * csz_sql )
{
	if (!query(csz_sql))
	{
		return -1;
	}
	return get_affected_rows();
}

bool database_mysql_t::query( const char * csz_data, int n_length /*= 0*/ )
{
	if (n_length == 0)
	{
		n_length = (int)strlen(csz_data);
	}
	return !(mysql_real_query((MYSQL *)m_mysql, csz_data, n_length));        // 查詢成功返回0
}

int database_mysql_t::get_affected_rows()
{
	return static_cast<int>(mysql_affected_rows((MYSQL *)m_mysql));
}

bool database_mysql_t::autocommit( bool bflag )
{
	return !(mysql_autocommit((MYSQL *)m_mysql, bflag));
}

bool database_mysql_t::commit()
{
	return !(mysql_commit((MYSQL *)m_mysql));
}

bool database_mysql_t::rollback()
{
	return !(mysql_rollback((MYSQL *)m_mysql));
}
//創建數據庫
bool database_mysql_t::create_db( const char * csz_db )
{
	char sz_temp[50] = {0};
	int n_len = sprintf(sz_temp, "create database %s", csz_db);
	return query(sz_temp, n_len);
}

bool database_mysql_t::drop_db( const char * csz_db )
{
	char sz_temp[50] = {0};
	int n_len = sprintf(sz_temp, "drop database %s", csz_db);
	return query(sz_temp, n_len);
}

bool database_mysql_t::create_table( const char *csz_sql )
{
	return query(csz_sql);
}

bool database_mysql_t::drop_table( const char * csz_talbe )
{
	char sz_temp[50] = {0};
	int n_len = sprintf(sz_temp, "drop table %s", csz_talbe);
	return query(sz_temp, n_len);
}

const char * database_mysql_t::get_error()
{
	return mysql_error((MYSQL *)m_mysql);
}

unsigned int database_mysql_t::get_errno()
{
	return mysql_errno((MYSQL *)m_mysql);
}

bool database_mysql_t::has_db( const char * csz_db )
{
	res_t res = select("show databases");
	if (!res)
	{
		return false;
	}
	else
	{
		row_t row = 0;
		int num = res.row_num();
		for (int i=0; i<num; ++i)
		{
			row = res.get_next_row();
			if (!strcmp(csz_db, row[0]))
			{				
				return true;
			}
		}
		return false;
	}
}

bool database_mysql_t::has_table( const char * csz_table )
{
	res_t res = select("show tables");
	if (!res)
	{
		return false;
	}
	else
	{
		row_t row = 0;
		int num = res.row_num();
		for (int i=0; i<num; ++i)
		{
			row = res.get_next_row();
			if (!strcmp(csz_table, row[0]))
			{				
				return true;
			}
		}
		return false;
	}
}
//查詢結果集
res_t::res_t() : m_data(0)
{

}

res_t::res_t( res_t& res )
{
	m_data = res.m_data;
	res.m_data = 0;
}

res_t::res_t( void *res )
{
	m_data = res;
}

res_t::~res_t()
{
	erase();
}

res_t& res_t::operator=( res_t& res)
{
	erase();
	m_data = res.m_data;
	res.m_data = 0;
	return *this;
}

int res_t::row_num()
{
	return static_cast<int>(mysql_num_rows((MYSQL_RES *)m_data));
}

int res_t::field_num()
{
	return static_cast<int>(mysql_num_fields((MYSQL_RES *)m_data));
}

unsigned long * res_t::field_lengths()
{
	return mysql_fetch_lengths((MYSQL_RES *)m_data);
}

row_t res_t::get_next_row()
{
	return mysql_fetch_row((MYSQL_RES *)m_data);
}

row_t res_t::get_row( int n_offset )
{
	mysql_data_seek((MYSQL_RES *)m_data, n_offset);
	return get_next_row();
}

row_t res_t::operator[]( int n_offset )
{
	return get_row(n_offset);
}

res_t::operator bool( void )
{
	return m_data ? true : false;
}

void res_t::erase()
{
	if (m_data)
	{
		mysql_free_result((MYSQL_RES *)m_data);
		m_data = 0;
	}
}

三、使用示例




// main.cpp : 定義控制檯應用程序的入口點。

#include "stdafx.h"
#include <iostream>
#include <database_mysql.h>

int _tmain(int argc, _TCHAR* argv[])
{
	
    database_mysql_t m_MysqlDb;
    if (!m_MysqlDb.connet("127.0.0.1", "root", "123456", "epidemic_deduction"))
    {	
	    return 0;
    }
    m_MysqlDb.set_char_set("utf8");

	std::ostringstream sql;
	sql << "insert into frame_list(id,num) values(\""
		<< 1000001<<"\",\"" <<10<<"\")";
	if (m_MysqlDb.insert(sql.str().c_str())==-1)
	{
        std::cout << database.get_error();
	}

    m_MysqlDb.dis_connect();

	return 0;
}

批量插入示例

void BatchWriteExpData(std::vector<std::string> expDatas)
{
	std::cout << "start batch insert expdata[" << expDatas.size() << "]" << std::endl;
	batch_insert_adapter_t* adapter = new batch_insert_adapter_t(&m_MysqlDb);
	adapter->begin_add_field("exp_data_list");    //插入信息
	adapter->add_field("id");
	adapter->add_field("step_id");
	adapter->add_field("exp_id");
	adapter->add_field("src_id");
	adapter->add_field("tgt_id");
	adapter->add_field("behaior_type");
	adapter->add_field("time");
	adapter->end_add_field();

	for (std::vector<std::string>::iterator it = expDatas.begin(); it != expDatas.end(); ++it)
	{
		std::vector<std::string> dataList = vStringSplit(*it);
		adapter->begin_add_row();
		adapter->add_value(dataList.at(0));  
		adapter->add_value(dataList.at(1)); 
		adapter->add_value(dataList.at(2)); 
		adapter->add_value(dataList.at(3)); 
		adapter->add_value(dataList.at(4)); 
		adapter->add_value(dataList.at(5)); 
		adapter->add_value(dataList.at(6)); 
		adapter->end_add_row();
	}

	adapter->flush();
	delete adapter;
	std::cout << "Batch insert success" << std::endl;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章