TinyWebSever源码逐行注释(六)_ sql_connection.cpp

前言

项目源码地址
项目详细介绍

项目简介:

Linux下C++轻量级Web服务器,助力初学者快速实践网络编程,搭建属于自己的服务器.

  1. 使用 线程池 + 非阻塞socket + epoll(ET和LT均实现) + 事件处理(Reactor和模拟Proactor均实现) 的并发模型
  2. 使用状态机解析HTTP请求报文,支持解析GET和POST请求
  3. 访问服务器数据库实现web端用户注册、登录功能,可以请求服务器图片和视频文件
  4. 实现同步/异步日志系统,记录服务器运行状态
  5. 经Webbench压力测试可以实现上万的并发连接数据交换

sql_connection.cpp用于实现数据库的连接池。主要内容如下:

1.数据库连接池

  • 单例模式,保证唯一
  • list实现连接池
  • 连接池为静态大小
  • 互斥锁实现线程安全

2.校验

  • HTTP请求采用POST方式
  • 登录用户名和密码校验
  • 用户注册及多线程注册安全

原项目地址的注释较少不适合初学者,于是我将每行都加上了注释帮助大家更好的理解:

cpp 复制代码
#include <mysql/mysql.h> // 包含 MySQL 库,用于和 MySQL 数据库交互
#include <stdio.h>       // 标准输入输出库
#include <string>        // C++ 字符串库
#include <string.h>      // C 字符串处理库
#include <stdlib.h>      // 标准库,包含内存分配、进程控制等
#include <list>          // C++ STL 的 list 容器,用于存储 MySQL 连接
#include <pthread.h>     // 线程库,用于多线程同步
#include <iostream>      // C++ 标准输入输出流
#include "sql_connection_pool.h" // 连接池头文件

using namespace std; // 使用标准命名空间

// 构造函数,初始化成员变量
connection_pool::connection_pool()
{
	m_CurConn = 0;  // 当前已使用的连接数
	m_FreeConn = 0; // 当前空闲的连接数
}

// 获取连接池实例(单例模式)避免重复创建连接池对象,进而管理和复用 MySQL 连接。
connection_pool *connection_pool::GetInstance()
{
	static connection_pool connPool; // 静态实例,保证全局唯一
	return &connPool; // 返回连接池的指针
}

// 构造初始化函数,设置连接池的相关配置
void connection_pool::init(string url, string User, string PassWord, string DBName, int Port, int MaxConn, int close_log)
{
	// 保存数据库连接的参数
	m_url = url;               // 数据库主机地址
	m_Port = Port;             // 端口号
	m_User = User;             // 数据库用户名
	m_PassWord = PassWord;     // 数据库密码
	m_DatabaseName = DBName;   // 数据库名
	m_close_log = close_log;   // 是否关闭日志

	// 创建最大连接数个 MySQL 连接并加入连接池
	for (int i = 0; i < MaxConn; i++)
	{
		MYSQL *con = NULL;
		con = mysql_init(con); // 初始化 MySQL 连接

		if (con == NULL) // 如果初始化失败,打印错误日志并退出程序
		{
			LOG_ERROR("MySQL Error");
			exit(1);
		}

		// 连接到 MySQL 数据库
		con = mysql_real_connect(con, url.c_str(), User.c_str(), PassWord.c_str(), DBName.c_str(), Port, NULL, 0);

		if (con == NULL) // 如果连接失败,打印错误日志并退出程序
		{
			LOG_ERROR("MySQL Error");
			exit(1);
		}

		// 将成功连接的 MySQL 连接加入连接池列表
		connList.push_back(con);
		++m_FreeConn; // 增加空闲连接数
	}

	// 初始化信号量,用于控制连接的获取和释放
	reserve = sem(m_FreeConn); 

	m_MaxConn = m_FreeConn; // 设置最大连接数
}

// 从连接池中获取一个可用的 MySQL 连接
MYSQL *connection_pool::GetConnection()
{
	MYSQL *con = NULL;

	if (0 == connList.size()) // 如果连接池为空,返回 NULL
		return NULL;

	reserve.wait(); // 等待信号量,如果没有空闲连接则等待

	lock.lock(); // 加锁,防止多线程同时操作连接池

	// 从连接池中取出一个连接
	con = connList.front(); 
	connList.pop_front(); // 移除最前面的连接

	--m_FreeConn; // 空闲连接数减少
	++m_CurConn;  // 使用中的连接数增加

	lock.unlock(); // 解锁
	return con;    // 返回获取的连接
}

// 释放当前使用的 MySQL 连接,将其放回连接池
bool connection_pool::ReleaseConnection(MYSQL *con)
{
	if (NULL == con) // 如果连接为空,返回 false
		return false;

	lock.lock(); // 加锁,防止多线程同时操作连接池

	// 将连接放回连接池
	connList.push_back(con);
	++m_FreeConn; // 空闲连接数增加
	--m_CurConn;  // 使用中的连接数减少

	lock.unlock(); // 解锁

	reserve.post(); // 释放信号量,通知等待的线程有连接可用
	return true;
}

// 销毁连接池,关闭所有 MySQL 连接
void connection_pool::DestroyPool()
{
	lock.lock(); // 加锁,防止其他线程操作连接池
	if (connList.size() > 0)
	{
		// 遍历连接池中的所有连接,逐一关闭
		list<MYSQL *>::iterator it;
		for (it = connList.begin(); it != connList.end(); ++it)
		{
			MYSQL *con = *it;
			mysql_close(con); // 关闭 MySQL 连接
		}
		m_CurConn = 0; // 重置已使用连接数
		m_FreeConn = 0; // 重置空闲连接数
		connList.clear(); // 清空连接池列表
	}

	lock.unlock(); // 解锁
}

// 返回当前空闲的连接数
int connection_pool::GetFreeConn()
{
	return this->m_FreeConn; // 返回空闲连接数
}

// 析构函数,销毁连接池,释放所有连接
connection_pool::~connection_pool()
{
	DestroyPool(); // 调用销毁连接池的函数
}

// RAII 机制,自动管理 MySQL 连接的获取和释放
connectionRAII::connectionRAII(MYSQL **SQL, connection_pool *connPool){
	*SQL = connPool->GetConnection(); // 获取一个数据库连接并赋值给传入的指针

	conRAII = *SQL; // 保存获取到的连接
	poolRAII = connPool; // 保存连接池的引用
}

// 析构函数,自动释放连接回连接池
connectionRAII::~connectionRAII(){
	poolRAII->ReleaseConnection(conRAII); // 将连接放回连接池
}
相关推荐
裕晟资质规划16 小时前
首次办理军工保密资质:咨询服务选择要点与全流程交付清单(评估框架)
大数据·运维·服务器·网络·数据库·经验分享
旖旎夜光16 小时前
LCR 173:在点名(二分查找) —— 题解
数据结构·c++·算法·leetcode·二分查找
Lazionr17 小时前
模板进阶:深入理解模板机制
c++·windows
运维全栈笔记19 小时前
Vue + Spring Boot 前后端分离项目部署笔记(若依 RuoYi-Vue 3.9.2)
运维·服务器·vue.js·spring boot·笔记·开源·开源软件
豆沙沙包?1 天前
C++~~~stack容器、queue容器、list容器(p45-P56)
c++·windows·list
Data_Journal1 天前
用于网页抓取的 Node-unblocker
大数据·开发语言·数据库·python·scrapy
涤生大数据1 天前
一次“没有运行日志”的DolphinScheduler任务失败排查
大数据·数据库·人工智能·状态模式
专注API从业者1 天前
告别人工盯品!借助 Open Claw 搭建电商商品自动化监控与数据分析系统(完整可运行源码)
大数据·运维·数据库·数据分析·自动化
Frank_refuel1 天前
【C++八股】面向对象
开发语言·c++
h_a_o777oah1 天前
【图论】Tarjan 缩点:解决有向图中环的问题
c++·算法·图论·acm·强连通分量·缩点·tarjan