数据库连接池(二)

devtools/2024/11/27 18:28:25/

数据库连接池(二)

  • 一、配置项目所需的外部库和头文件
  • 二、实现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静态局部变量定义一个连接池,因为创建一个静态局部变量是线程安全的,在底层会创建操作加锁,保证操作是原子的,静态局部变量只会定义一次,只有在调用获取连接池的接口时才会定义。这符合线程安全的懒汉单例模式,返回静态局部线程池的地址。
线程池中封装了的成员变量有:想要访问数据库服务器的ip地址,用于数据库访问的端口号,用于连接认证的用户名和用户名密码,想要访问的数据库名称,用于初始化空闲连接队列的初始连接量,限制连接数量的最大连接量,当前创建了的连接数量,连接的最大空闲时间,连接的超时时间,用于等待空闲连接池不为空的条件变量,用于等待连接池是空的条件变量,用于保证线程互斥的互斥锁以及存储空闲连接的队列。
线程池中封装了的成员方法有:
连接池的构造函数,通过加载配置文件初始化连接池的各成员变量。
为外部提供获取连接池的接口函数。
为消费线程提供的消费连接的线程函数。
为生产线程提供的生产连接的生产函数。
为销毁线程提供的销毁连接的销毁函数。
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=CQUPTyyy
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.ppmy.cn/devtools/137460.html

相关文章

计算机毕业设计Python+大模型美食推荐系统 美食可视化 美食数据分析大屏 美食爬虫 美团爬虫 机器学习 大数据毕业设计 Django Vue.js

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

Web 学习笔记 - 网络安全

前言 作为 前端开发者&#xff0c;了解一点 Web 安全方面的基本知识是有很必要的&#xff0c;未必就要深入理解。本文主要介绍常见的网络攻击类型&#xff0c;不作深入探讨。 正文 网络攻击的形式种类繁多&#xff0c;从简单的网站敏感文件扫描、弱口令暴力破解&#xff0c;…

Vue进阶面试题目(四)

1. 什么是双向绑定? Vue 双向绑定的原理是什么? 双向绑定是一种数据绑定机制&#xff0c;指的是视图和数据之间可以相互同步。即&#xff0c;当模型数据&#xff08;Model&#xff09;发生变化时&#xff0c;视图&#xff08;View&#xff09;会自动更新&#xff1b;反之&am…

【设计模式】【结构型模式(Structural Patterns)】之桥接模式(Bridge Pattern

1. 设计模式原理说明 桥接模式&#xff08;Bridge Pattern&#xff09; 是一种结构型设计模式&#xff0c;用于将抽象部分与实现部分分离&#xff0c;使它们可以独立变化。这种模式有助于解决因实现细节的变化而导致的代码膨胀问题。桥接模式的核心思想是通过组合而不是继承来…

Edge浏览器保留数据,无损降级退回老版本+禁止更新教程(适用于Chrome)

3 个月前阿虚就已经写文章告警过大家&#xff0c;Chromium 内核的浏览器将在 127 以上版本开始限制仍在使用 Manifest V2 规范的扩展&#xff1a;https://mp.weixin.qq.com/s/v1gINxg5vMh86kdOOmqc6A 像是 IDM、油猴脚本管理器、uBblock 等扩展都会受到影响&#xff0c;后续将无…

深度学习中的卷积神经网络:原理、结构与应用

&#x1f35e;引言 卷积神经网络&#xff08;Convolutional Neural Networks&#xff0c;CNNs&#xff09;是深度学习领域中的一类经典神经网络结构&#xff0c;尤其在图像识别、语音识别等任务中得到了广泛的应用。CNN通过模仿生物视觉系统处理信息的方式&#xff0c;能够高效…

无人机:智能航点规划技术!

一、核心技术 环境感知技术 环境感知是智能航点规划的基础&#xff0c;通过传感器&#xff08;如雷达、摄像头、激光雷达等&#xff09;实时收集飞行环境的信息&#xff0c;包括地形、障碍物、天气等。 这些信息被用于构建飞行环境的数字模型&#xff0c;为后续的航点规划提…

Python学习34天

import random class Game: peo0 rob0 # # def __init__(self,peo,rob): # self.peopeo # self.robrob def Play(self): """ 石头剪刀布游戏&#xff0c;0代表石头&#xff0c;1代见到&#xff0c;2代表石头 …