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); // 将连接放回连接池
}
相关推荐
gywl14 分钟前
openEuler VM虚拟机操作(期末考试)
linux·服务器·网络·windows·http·centos
了一li1 小时前
Qt中的QProcess与Boost.Interprocess:实现多进程编程
服务器·数据库·qt
日记跟新中2 小时前
Ubuntu20.04 修改root密码
linux·运维·服务器
唐小旭2 小时前
服务器建立-错误:pyenv环境建立后python版本不对
运维·服务器·python
码农君莫笑2 小时前
信管通低代码信息管理系统应用平台
linux·数据库·windows·低代码·c#·.net·visual studio
明 庭2 小时前
Ubuntu下通过Docker部署NGINX服务器
服务器·ubuntu·docker
BUG 4042 小时前
Linux——Shell
linux·运维·服务器
007php0072 小时前
Go语言zero项目部署后启动失败问题分析与解决
java·服务器·网络·python·golang·php·ai编程
yang_shengy2 小时前
【JavaEE】网络(6)
服务器·网络·http·https