当前位置: 首页 > article >正文

数据库连接池(二)

数据库连接池(二)

  • 一、配置项目所需的外部库和头文件
  • 二、实现Connection类
  • 三、实现线程安全懒汉式单例模式的连接池
  • 四、实现连接池的构造函数

一、配置项目所需的外部库和头文件

需要先安装MySQL Server mysql库和头文件是安装MySQL Server才有。
1.右键项目-C/C++ -常规-添加包含目录 中填写mysql.h头文件的路径
提示文件搜索可以使用everything
在这里插入图片描述
2.右键项目-链接器-常规-添加库目录 填写libmysql.lib静态库的路径
在这里插入图片描述
3.右键项目-链接器-输入-添加依赖项 填写静态库的名称
在这里插入图片描述
4.将mysql.dll动态库拷贝到项目文件路径下
在这里插入图片描述

二、实现Connection类

1.定义一个Connection类实现对MySQL Server中数据库进行CURD的操作

#ifndef CONNECTION_H
#define CONNECTION_H

//雄关漫道真如铁,而今迈步从头越
#include <iostream>
#include <mysql.h>
#include <string>
#include <mutex>
#include "public.h"
class Connection {
public:
	//初始化连接
	Connection();
	//关闭连接
	~Connection();
	//传入MySQL Server的ip地址,端口,用户名,密码,数据库名称,建立访问数据库的连接
	bool connect(std::string ip, unsigned short port, std::string user, std::string password, std::string dbname);
	//传入sql更新数据库
	bool update(std::string sql);
	//传入sql查询数据库
	MYSQL_RES* query(std::string sql);
	//更新连接进入空闲状态的开始时间
	void refreshIdleStartTime();
	//获取连接进入空闲状态的开始时间
	clock_t getIdleTime();
private:
	MYSQL* conn_;//标识一个连接
	clock_t idleStartTime_;//连接空闲开始时间
 };
#endif

2.将Connetion类中成员函数的声明和实现分离。实现成员函数,包括实现连接的初始化,连接的析构销毁,建立与数据库的连接,通过SQL语句对数据库更新和查询的函数。

#include "Connection.h"
//构造函数初始化mysql连接
std::mutex mtx;
Connection::Connection()
{
	std::lock_guard<std::mutex> lock(mtx);
	conn_ = mysql_init(nullptr);
	if (conn_ == nullptr) {
		std::cout << "conn_ == nullptr" << std::endl;
	}
}
//析构函数将mysql连接关闭
Connection::~Connection()
{
	if (conn_ != nullptr)
		mysql_close(conn_);
}
//传入MySQL Server的ip地址,开放端口,用户名,用户名密码,及访问的数据库,与MySQL Server建立连接
bool Connection::connect(std::string ip, unsigned short port, std::string user, std::string password,std::string dbname)
{
	MYSQL* p = mysql_real_connect(conn_, ip.c_str(), user.c_str(),password.c_str(), dbname.c_str(), port, nullptr, 0);
	return p != nullptr;
}
//传入的SQL语句对数据库进行更新
bool Connection::update(std::string sql)
{
	if (mysql_query(conn_, sql.c_str()))
	{
		LOG("更新失败:" + sql);
		return false;
	}
	return true;
}
//传入查询的SQL语句获取查询的数据
MYSQL_RES* Connection::query(std::string sql)
{
	if (mysql_query(conn_, sql.c_str()))
	{
		LOG("查询失败:" + sql);
		return nullptr;
	}
	return mysql_use_result(conn_);
}
//刷新连接的空闲开始时间
void Connection::refreshIdleStartTime() {
	idleStartTime_ = clock();
}
//获取连接进入空闲状态的时间
clock_t Connection::getIdleTime() { return clock()-idleStartTime_; }

三、实现线程安全懒汉式单例模式的连接池

1.将构造函数私有化。
2.将线程池的拷贝构造函数删除。
3.创建获取单例对象的接口函数。
使用static的局部变量定义一个连接池,因为定义一个静态的局部变量是线程安全的,底层的操作是会加锁,保证操作是原子的,局部静态变量只会定义一次,只有在调用获取连接池的接口函数时才会定义。这符合线程安全的懒汉单例模式,返回静态局部线程池的地址。
ConnectionPool.h

#ifndef CONNECTIONPOOL_H
#define CONNECTIONPOOL_H

#include "Connection.h"
#include <thread>
#include <queue>
#include <condition_variable>
#include <mutex>
#include <functional>
#include <atomic>
//将连接池设计成单例模式
class ConnectionPool {
private:
	//初始化线程池
	ConnectionPool();
	//加载配置文件初始化连接池
	bool loadConfigFile();
public:
	//释放连接池资源
	~ConnectionPool();
	//给外部提供获取线程池的接口
	static ConnectionPool* getConnectionPool();

	//为外部消费线程提供消费连接函数接口
	std::shared_ptr<Connection> consumeFunc();
	//为生产线程提供生产连接函数
	void produceFunc();
	//为销毁线程提供的销毁连接函数
	void destroyFunc();

	ConnectionPool(const Connection&)= delete;
	ConnectionPool& operator=(const Connection&)= delete;
private:
	std::string ip_;//MySQL Server的ip地址
	unsigned short port_;//MySQL Server开放的端口号
	std::string userName_;//用户名   用户名密码数据库用于连接认证
	std::string passWord_;//用户对应的密码
	std::string dbName_;//访问的数据库

	int initConnSize_;//初始连接量
	int maxConnSize_;//最大连接量
	int maxIdleTime_;//连接的最大空闲时间
	int connTimeOut_;//申请连接的超时时间
	std::atomic_int curConnSize_;//当前连接的数量

	std::condition_variable empty_;//等待连接数量不等于最大连接量时使用的条件变量
	std::condition_variable notEmpty_;//等待空闲连接队列不为空时使用的条件变量
	std::mutex mtx_;//保证线程互斥使用的互斥锁
	std::queue<Connection*> idleConnectionQue_;//空闲连接队列
};

#endif

四、实现连接池的构造函数

1.通过加载配置文件获取连接池的属性,对连接池进行初始化。

#配置文件  
#配置线程池的属性
ip=127.0.0.1
port=3306
userName=root
passWord=CQUPTyyy591420
dbName=chat
initConnSize=10
maxConnSize=1024
#秒
maxIdleTime=60 
#毫秒
connTimeOut=100

#include "ConnectionPool.h"
//加载配置文件
bool ConnectionPool::loadConfigFile() {
	
	FILE* fp = fopen("mysql.ini", "r");
	if (fp==nullptr) {
		LOG("mysql.init open fail");
		return false;
	}
	while (!feof(fp)) {
		char buffer[1024];
		fgets(buffer, sizeof(buffer), fp);
		std::string s = buffer;
		int startIndex = s.find("=");
		if (startIndex == std::string::npos)continue;
		int endIndex = s.find("\n");
		if (endIndex == std::string::npos)continue;
		std::string key = s.substr(0, startIndex);
		std::string value = s.substr(startIndex + 1, endIndex - 1 - startIndex);
		if (key == "ip")ip_ = value;
		else if (key == "port")port_ = std::stoi(value);
		else if (key == "userName")userName_ = value;
		else if (key == "passWord")passWord_ = value;
		else if (key == "dbName")dbName_ = value;
		else if (key == "initConnSize")initConnSize_ = stoi(value);
		else if (key == "maxConnSize")maxConnSize_ = stoi(value);
		else if (key == "maxIdleTime")maxIdleTime_ = stoi(value);
		else if (key == "connTimeOut")connTimeOut_ = stoi(value);
	}
	return true;
}

2.实现构造函数,通过加载配置文件函数对连接池的参数属性进行初始化,创建initSize个连接放到空闲连接队列中,并启动生产连接的线程和销毁连接的线程。

//初始化连接池
ConnectionPool::ConnectionPool()
	:curConnSize_(0) {
	//加载配置文件,初始连接池的属性
	if (loadConfigFile()==false) {
		LOG("loadConfigFile fail");
		exit(1);
	}
	for (int i = 0; i < initConnSize_; ++i) {
		Connection* p = new Connection();
		p->connect(ip_, port_, userName_, passWord_, dbName_);
		p->refreshIdleStartTime();
		idleConnectionQue_.push(p);
		curConnSize_++;
	}
	std::thread produceThread(std::bind(&ConnectionPool::produceFunc,this));
	std::thread destroyThread(std::bind(&ConnectionPool::destroyFunc, this));
	produceThread.detach();
	destroyThread.detach();
}

http://www.kler.cn/a/408324.html

相关文章:

  • 数据库-基础理论
  • Vite基本概要
  • <硬件有关> 内存攒机认知入门,内存的选择 配置 laptop PC 服务器
  • 从零开始-VitePress 构建个人博客上传GitHub自动构建访问
  • Java爬虫:获取商品详情的实践之旅
  • 力扣2388. 将表中的空值更改为前一个值
  • Vue v-if 与 v-for 使用指南:优先级、注意事项及常见错误防范
  • Independent Component Analysis
  • 如何利用ros搭建虚拟场景通过仿真机器人完成一次简单的SLAM建图、导航规划(超简单)?——学习来源:机器人工匠阿杰
  • SpringBoot多文件上传
  • springboot3如何集成knife4j 4.x版本及如何进行API注解
  • Spring集成测试
  • 电子应用设计方案-21:智能取暖系统方案设计
  • C语言之函数的参数
  • C语言:深入理解指针
  • 青少年强网杯线上ctf-crypto-wp
  • Python爬虫进阶实战项目:使用青果网代理高效爬取某手办网详情数据
  • 《那个让服务器“跳舞”的bug》
  • 神经网络(系统性学习二):单层神经网络(感知机)
  • 【CS61A 2024秋】Python入门课,全过程记录P2(Week3开始,更新中2024/11/24)
  • React(五)——useContecxt/Reducer/useCallback/useRef/React.memo/useMemo
  • 11.19机器学习_逻辑回归
  • harbor和docker配置https访问
  • Git | 通过Gihub+git组合来学习理解团队项目合作中分支的创建、合并、删除操作
  • 【C语言】指针1
  • 嵌入式开发中Java可以替代Qt吗?