首页 > 数据库 >【c++】Linux MySQL连接池

【c++】Linux MySQL连接池

时间:2024-08-07 22:30:12浏览次数:12  
标签:std queryResult string nullptr c++ MySQL MySQLConnection mysqlConn 连接池

#ifndef MYSQLCONNECTION_H
#define MYSQLCONNECTION_H
#include <iostream>
#include <mysql.h>
#include <vector>

class MySQLConnection
{
public:
	/// <summary>
	/// 初始化连接
	/// </summary>
	MySQLConnection();
	MySQLConnection(MySQLConnection& another) = delete;
	MySQLConnection& operator=(MySQLConnection& another) = delete;
	MySQLConnection(MySQLConnection&& another);
	MySQLConnection& operator=(MySQLConnection&& another);
	//断开连接
	~MySQLConnection();
	/// <summary>
	/// 连接服务器
	/// </summary>
	/// <param name="host">主机</param>
	/// <param name="user">用户名</param>
	/// <param name="pwd">密码</param>
	/// <param name="dbName">数据库名</param>
	/// <param name="port">端口(default=3306)</param>
	/// <returns></returns>
	bool connect(std::string host, std::string user, std::string pwd, std::string dbName, unsigned int port = 3306);
    
    bool disconnect();
	/// <summary>
	/// 更新数据库:insert、delete、update
	/// </summary>
	/// <param name="sqlUpdate">增删改sql语句</param>
	/// <returns></returns>
	bool update(std::string sqlUpdate);
	/// <summary>
	/// 查询数据库
	/// </summary>
	/// <param name="sqlQuery">查询sql语句</param>
	/// <returns></returns>
	bool query(std::string sqlQuery);
	/// <summary>
	/// 查看所有字段名
	/// </summary>
	/// <returns></returns>
	std::vector<std::string> fields();
	/// <summary>
	/// 遍历查询数据集,指向下一条记录
	/// </summary>
	/// <returns></returns>
	bool next();
	/// <summary>
	/// 通过字段的index获取值
	/// </summary>
	/// <param name="index"></param>
	/// <returns></returns>
	std::string value(unsigned int index);
	/// <summary>
	/// 通过字段名获取字段值
	/// </summary>
	/// <param name="fieldName"></param>
	/// <returns></returns>
	std::string value(std::string fieldName);
	/// <summary>
	/// 开启事务操作,设置成手动提交、创建保存点
	/// </summary>
	/// <returns></returns>
	bool startTransaction();
	/// <summary>
	/// 事务提交
	/// </summary>
	/// <returns></returns>
	bool commit();
	/// <summary>
	/// 事务回滚
	/// </summary>
	/// <returns></returns>
	bool rollback();
private:
	/// <summary>
	/// 清空上一次查询结果
	/// </summary>
	void freeQueryResult();

	MYSQL* mysqlConn = nullptr;	//MySQL连接
	MYSQL_RES* queryResult = nullptr;	//查询结果集
	std::vector<std::string> fieldNames;	//当前结果集的所有字段名
	MYSQL_ROW queryResultRow = nullptr;	//当前查询记录
};

#endif
#include "MySQLConnection.h"

MySQLConnection::MySQLConnection()
{
	mysqlConn = mysql_init(mysqlConn);	//初始化连接
}

MySQLConnection::MySQLConnection(MySQLConntion&& another)
{
    this->mysqlConn=another.mysqlConn;
    this->queryResult=another.mysqlConn;
    another->mysqlConn=nullptr;
    another->mysqlConn=nullptr;
}

MySQLConnection& MySQLConnection::operator=(MySQLConntion&& another)
{
    if(this->mysqlConn!=another.mysqlConn)
    {
        if(this->mysqlConn!=nullptr)
        {
            delete this->mysqlConn;
            this->mysqlConn=another.mysqlConn;
           	another.mysqlConn=nullptr;
        }
        if(this->queryResult!=nullptr)
        {
            mysql_free_result(this->queryResult);
            this->queryResult=another.queryResult;
		   this->fieldNames.swap(another.fieldNames);
        }
    }
    return *this;
}

MySQLConnection::~MySQLConnection()
{
	if (mysqlConn != nullptr)
	{
		mysql_close(mysqlConn);	//关闭连接
		freeQueryResult();	//清空结果集queryResult和结果集中字段fieldNames
	}
}

bool MySQLConnection::connect(std::string host, std::string user, std::string pwd, std::string dbName, unsigned int port)
{
	mysqlConn = mysql_real_connect(mysqlConn, host.c_str(), user.c_str(), pwd.c_str(), dbName.c_str(), 
		port, nullptr, 0);	//失败返回NULL
	return mysqlConn != nullptr;	
}

bool MySQLConnection::disconnect()
{
    if (mysqlConn != nullptr)
	{
		mysql_close(mysqlConn);	//关闭连接
		freeQueryResult();	//清空结果集queryResult和结果集中字段fieldNames
	}
}

bool MySQLConnection::update(std::string sqlUpdate)
{
	return mysql_query(mysqlConn, sqlUpdate.c_str()) == 0;	//修改成功返回0,否则返回非0
}

bool MySQLConnection::query(std::string sqlQuery)
{
	if (mysql_query(mysqlConn, sqlQuery.c_str()) != 0)	//查询成功返回非0
	{
		return false;
	}

	freeQueryResult();	//清空上次的查询结果和字段名
	queryResult = mysql_store_result(mysqlConn);	//从MySQL服务器把查询结果拉到客户端
	return true;
}

std::vector<std::string> MySQLConnection::fields()
{
	if (queryResult == nullptr)
	{
		return fieldNames;
	}

	std::vector<std::string>(0).swap(fieldNames);	//清空上次查询记录的字段
	int colCount = mysql_num_fields(queryResult);	//获取字段的个数
	MYSQL_FIELD* fields = mysql_fetch_fields(queryResult);	//获取字段名数组

	for (int i = 0; i < colCount; i++)
	{
		fieldNames.emplace_back(fields[i].name);	//遍历存储字段名
	}
	return fieldNames;
}

bool MySQLConnection::next()
{
	if (queryResult == nullptr)
	{
		return false;
	}

	queryResultRow = mysql_fetch_row(queryResult);	//从结果集取下一条记录
	return queryResultRow != nullptr;	//如果已经取完,返回NULL
}

std::string MySQLConnection::value(unsigned int index)
{
	if (queryResult == nullptr || queryResultRow == nullptr)
	{
		return std::string();	//返回空字符串
	}

	if (index < 0 || index >= mysql_num_fields(queryResult))
	{
		return std::string();
	}

	//防止某个字段的值包含'\0',这样string(char*)到'\0'就会停止
	// char str[] = { '1', '2','3','4','5','\0','6','7' };
	//std::string s(str);	//12345
	//string(char*,int)遇到'\0'也不会停止,会把指定个数的char都包含
	unsigned long* colRealLengths = mysql_fetch_lengths(queryResult);	//获取该字段值的实际长度
	return std::string(queryResultRow[index], colRealLengths[index]);	
}

std::string MySQLConnection::value(std::string fieldName)
{
	if (queryResult == nullptr || queryResultRow == nullptr)
	{
		return std::string();
	}

	if (fieldName == "")
	{
		return std::string();
	}

	for (unsigned int i = 0; i < fieldNames.size(); i++)
	{
		if (fieldName == fieldNames[i])
		{
			return value(i);
		}
	}
	return std::string();
}

void MySQLConnection::freeQueryResult()
{
	if (queryResult != nullptr)
	{
		mysql_free_result(queryResult);
		std::vector<std::string>(0).swap(fieldNames);
	}
}

bool MySQLConnection::startTransaction()
{
	return mysql_autocommit(mysqlConn, 0) == 0;
}

bool MySQLConnection::commit()
{
	return mysql_commit(mysqlConn) == 0;
}

bool MySQLConnection::rollback()
{
	return mysql_rollback(mysqlConn) == 0;
}
#ifndef MYSQLCONNPOOL_H
#define MYSQLCONNPOOL_H
#include "MySQLConntion.h"
#include<pthread.h>
#include<assert.h>
#include<vector>

class MysqlConnPool
{
private:
    int m_minSize;
    int m_maxSize;
    int m_size;
    int m_countLocked;
    vector<MySQLConntion> m_conns;
    vector<pthread_mutex_t> m_mutexs;
    pthread_t pthManage;
    
private:
    void manage(void* arg)	//连接池size调整
    {
        while(true)
        {
            if(m_countLocked>0.8*m_size && 1.2*m_size<=m_maxSize)
       		{
                //增加连接
                int i=m_size;
                m_size=1.2*m_size;
           	   	for(;i<m_size;++i)
                {
                    MySQLConntion con;
                    m_conns.push_back(con);
                    pthread_mutex_t mtx;
                    m_mutexs.push_back(mtx);
                }
       		}
       		else if(m_countLocked<0.4*m_size && 0.8*m_size>=m_minSize && 0.8*m_size<=m_maxSize)
       		{
           		//减少连接
                int i=m_size;
                m_size=0.8*m_size;
                while(i>m_size)
                {
                    if(pthread_mutex_trylock(&m_mutexs[i])==0)
                    {
                        MySQLConntion con;
                        m_conns.push_back(con);
                        pthread_mutex_t mtx;
                        m_mutexs.push_back(mtx);    
                        --i;
                    }
                }
       		}
            
            sleep(5);	//每5s执行一次
        }
    }
	
public:
	MysqlConnPool(int minSize, int maxSize, int size):m_minSize(minSize),m_maxSize(maxSize),m_size(size)
	{
        assert(size>=m_minSize&&size<=m_maxSize);
        m_countLocked=0;
        for(int i=0;i<m_size;++i)
        {
          	MySQLConntion con;
            m_conns.push_back(con);
        }
        for(int i=0;i<m_size;++i)
        {
          	pthread_mutex_t mtx;
            m_mutexs.push_back(mtx);
        }
        
        pthread_create(&pthManage,NULL,manage,NULL);
	}

	~MysqlConnPoll()
	{
		freeconns();
         pthread_join(&pthManage,NULL);
	}

	// 初始化数据库连接池。
	bool initconns()
	{
         bool ret=true;
		//创建m_size个连接到db的连接
		for (int ii=0;ii<m_size;ii++)
		{
			ret=ret&&m_conns[ii].connect("127.0.0.1","root","root","dbtest");
		}
		//初始化m_size个互斥锁
		for(int i=0;i<m_size;i++)
		{
			if(pthread_mutex_init(&m_mutexs[i],NULL)!=0)
	  			return false;
		}
	
		return ret;
	}

	MySQLConnection* getconn()
	{
		//遍历连接队列,返回第一个可以上锁的连接(没有被其他线程使用)
		for(int i=0;i<m_size;i++)
		{
			if(pthread_mutex_trylock(&m_mutexs[i])==0)
             {
             	m_countLocked++;
                return &m_conns[i];
             }
		}
	
		return NULL;	//队列没有空闲连接
	}

	void freeconn(MySQLConnection* in_conn)
	{
		if(in_conn!=NULL)
		{
			for(int i=0;i<m_size;i++)
			{
	   			if(in_conn==&m_conns[i])
	   			{
	        		pthread_mutex_unlock(&m_mutexs[i]);
                     m_countLocked--;
	   			}
			}
		}
	}

	void freeconns()
	{
		for(int i=0;i<m_size;i++)
		{
             pthread_mutex_destroy(&m_mutexs[i]);	//互斥锁销毁
			m_conns[i].disconnect();	//连接断开
		}
         m_conns.clear();
         m_mutexs.clear();
         m_countLocked=0;
	}
};

#endif

标签:std,queryResult,string,nullptr,c++,MySQL,MySQLConnection,mysqlConn,连接池
From: https://www.cnblogs.com/wk2522466153/p/18347958

相关文章

  • 面向对象程序设计(C++)之 String 类
    1.String构造函数String可以理解为一个字符数组,在创建String类型变量的时候可以使用很多形式,因为String有很多实用的构造函数首先使用String类要包含头文件#include<string>接下来使用代码依次演示上述构造函数的用法: #include<iostream>#include<string>......
  • C++ SQL ORM
     测试代码 ////Createdbywwwon2024/8/7.//#include"sqlitepp/database.h"#include"sqlitepp/condition.h"#include<iostream>usingnamespacesqlitepp;usingnamespacesqlitepp::literals;enumclasstest_enum{hello};voi......
  • C++入门基础(完整版)含下卷
    C++入门基础hello各位未来的程序员大佬们,这一篇是详细介绍入门基础,和上一篇不同的是这一篇补完了引用的知识和inline,nullptr的知识,希望大家有所收获namespace的价值在C/C++中,变量、函数和后⾯要学到的类都是⼤量存在的,这些变量、函数和类的名称将都存在于全局作⽤域中......
  • C++ STL与string类
    一什么是STL?STL,全称是标准模板库(StandardTemplateLibrary),是C++标准库的一部分。STL提供了一些常用的数据结构和算法,帮助开发者更方便、高效地编写代码。通过使用STL,开发者不需要重复造轮子,可以直接使用已经优化好的组件,提高了代码的可读性和可维护性。二STL的六大组件1.......
  • node.js: mysql con in vscode
    mysqlscript:droptable`vuedustu`;CREATETABLE`vuedustu`(`stuId`int(11)NOTNULLAUTO_INCREMENTcomment'学生编号',`stuname`varchar(255)DEFAULTNULLcomment'学姓姓名',`stusex`varchar(255)DEFAULTNULLcomment'性别',......
  • VS设置 LLVM-Clang 编译器进行编译C++项目
    在VS中默认的C++编译器一般为MSVC编译器,可以根据自己的需要将其设置为LLVM-Clang编译器。主要有两种方案:1)直接使用VisualStudioInstaller来自动下载对应的Clang编译器和构建工具,后续无需再进行配置,便可直接使用。2)使用自己编译或者单独下载的LLVM-Clang编译器,以及通......
  • [Mysql]为什么性别不适合加索引
    大家都知道索引分聚集索引和非聚集索引,性别字段因为可重复肯定只能建立非聚集索引,然而因为非聚集索引叶子节点存储的是索引值和聚集索引值,需要回表。所以在性别这种辨别度较低的字段上建立索引,索引树可能只有两个节点,跟线性查找没有太大区别,并且因为回表的存在导致在聚集索引树和......
  • web页面中直接调用c++/c/go代码?【wasm】
    背景最近在做rosbag的可视化工具,网上找了个源码参考(foxglove)。成功down下来,跑起来了。于是乎,开始研究前后端代码;结果居然花了一下午没找到后端代码,不明白为什么纯web页面就可以解析rosbag(以前都是用node.js或者c++代码解析的)。过程在找了一下午之后,又回到了老办法;看netork,果然......
  • node.js: mysql sequelize in WebStorm 2023.1
    mysql:select*fromtutorials;#CREATETABLEIFNOTEXISTS`tutorials`(`id`INTEGERNOTNULLauto_increment,`title`VARCHAR(255),`description`VARCHAR(255),`published`TINYINT(1),`createdAt`DATETIMENOTNULL,`updatedAt`DATETIMENOTNULL,PRIMA......
  • kmp算法(c++)
    kmp算法的简单介绍从主串中快速找到与要找的串的相同位置如果使用暴力算法去求解这个问题,时间复杂度为O(i*j)=>很大kmp算法则是对这类问题的优化因整理过于麻烦,,详细的介绍可以参照这篇博客,,花时间看完就明白了,写的很棒!!!kmp算法详细介绍下面是自己学习的一些注意的地......