文章目录
校验 & 数据库连接池
数据库连接池
- 单例模式,保证唯一
- list实现连接池
- 连接池为静态大小
- 互斥锁实现线程安全
校验
- HTTP请求采用POST方式
- 登录用户名和密码校验
- 用户注册及多线程注册安全
共两个个class,分别是connection_pool和connectionRAII
一、头文件
#include <stdio.h>
#include <list>
#include <mysql/mysql.h>
#include <error.h>
#include <string.h>
#include <iostream>
#include <string>
#include "../lock/locker.h"
#include "../log/log.h"
using namespace std;
二、connectionRAII类
- RAII(Resource Acquisition Is Initialization)即资源获取即初始化,是一种C++编程技巧,用于管理资源。connectionRAII类依托于connection_pool类,用于在函数执行期间自动申请连接和自动释放连接,避免了手动申请和释放资源出现的错误和异常情况;
- 在创建connectionRAII对象时,它会自动调用connection_pool的GetConnection()方法来获取数据库连接;
- 在connectionRAII对象生命周期结束时,它会自动调用connection_pool的ReleaseConnection()方法来释放数据库连接。
1.类的定义
class connectionRAII{
public:
connectionRAII(MYSQL **con, connection_pool *connPool);
~connectionRAII();
private:
MYSQL *conRAII;
connection_pool *poolRAII;
};
2.构造函数与析构函数
构造函数,用于管理MySQL数据库连接的,采用资源获取即初始化(RAII)的方式进行自动化管理
在创建connectionRAII对象时,会自动获取一个数据库连接,并将其保存在conRAII中,同时也保存了连接池的指针,方便之后的释放操作
// 两个参数分别是:MYSQL类型的指针SQL和connection_pool类型的指针connPool
connectionRAII::connectionRAII(MYSQL **SQL, connection_pool *connPool){
*SQL = connPool->GetConnection();// 将从连接池中获取到的一个数据库连接赋值给SQL指向的内存空间
conRAII = *SQL;// 将SQL所指向的内存空间的内容赋值给了conRAII成员变量
poolRAII = connPool;// 将connPool所指向的内存空间的内容赋值给了poolRAII成员变量
}
析构函数,用于释放数据库连接资源。在connectionRAII对象被销毁时(例如,作用域结束或delete运算符调用),会自动调用该析构函数
在connectionRAII对象被销毁时,会自动释放其所持有的数据库连接,避免了内存泄漏等问题。同时,由于使用了connection pool,还可以提高程序的效率,避免频繁创建和销毁数据库连接带来的开销
connectionRAII::~connectionRAII(){
poolRAII->ReleaseConnection(conRAII);
}
二、connection_pool类
- 维护一个MySQL连接池,提供获取和释放连接的方法;
- 可以初始化连接池参数,包括URL、用户名、密码、数据库名、端口号、最大连接数等;
- 实现了单例模式,确保只有一个连接池实例存在;
- 通过使用锁和信号量控制并发访问连接池的线程安全问题。
1.类的定义
class connection_pool
{
public:
MYSQL *GetConnection(); //获取数据库连接
bool ReleaseConnection(MYSQL *conn); //释放连接
int GetFreeConn(); //获取连接
void DestroyPool(); //销毁所有连接
//单例模式
static connection_pool *GetInstance();
void init(string url, string User, string PassWord, string DataBaseName, int Port, int MaxConn, int close_log);
private:
connection_pool();
~connection_pool();
int m_MaxConn; //最大连接数
int m_CurConn; //当前已使用的连接数
int m_FreeConn; //当前空闲的连接数
locker lock;
list<MYSQL *> connList; //连接池
sem reserve;
public:
string m_url; //主机地址
string m_Port; //数据库端口号
string m_User; //登陆数据库用户名
string m_PassWord; //登陆数据库密码
string m_DatabaseName; //使用数据库名
int m_close_log; //日志开关
};
2.构造函数与析构函数
构造函数,成员变量m_CurConn和m_FreeConn被初始化为0
connection_pool::connection_pool()
{
m_CurConn = 0; //当前已使用的连接数
m_FreeConn = 0; //当前空闲的连接数
}
析构函数,对连接池进行释放
connection_pool::~connection_pool()
{
DestroyPool();
}
3.GetInstance()
在整个应用程序中,只需要调用GetInstance()方法获取该连接池的唯一实例,然后就可以使用该实例执行数据库操作
connection_pool *connection_pool::GetInstance()
{
// static确保整个应用程序中只有一个数据库连接池
static connection_pool connPool;
return &connPool;
}
4.init()
用于初始化连接池
在整个程序生命周期中,只需要调用一次init()
函数,就可以初始化连接池,然后在需要访问数据库时,从连接池中获取连接,执行完操作后,将连接归还到连接池中以供下次使用
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;
// 创建了指定数量的数据库连接,并将连接添加到connList列表中
for (int i = 0; i < MaxConn; i++)
{
MYSQL *con = NULL;
con = mysql_init(con);
// 如果连接创建失败,则会输出错误信息并立即退出程序
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);
}
// 如果成功创建连接,则将连接添加到connList列表中
connList.push_back(con);
// 并将m_FreeConn计数器加1,表示新增一个可用连接
++m_FreeConn;
}
// 创建了一个名为reserve的信号量,初始值为m_FreeConn,表示当前空闲连接数
reserve = sem(m_FreeConn);
// m_MaxConn变量被设置为m_FreeConn,表示最大连接数也是当前可用连接数
m_MaxConn = m_FreeConn;
}
5.GetConnection()
数据库连接池中获取可用连接的函数。当有请求时,它会从数据库连接池(connList)中返回一个可用连接(con),并更新使用和空闲连接数
//当有请求时,从数据库连接池中返回一个可用连接,更新使用和空闲连接数
MYSQL *connection_pool::GetConnection()
{
MYSQL *con = NULL;
// 检查连接池中是否有可用连接,如果没有则返回NULL表示没有可用连接
if (0 == connList.size())
return NULL;
// 在没有可用连接的情况下会将线程阻塞以等待可用连接
reserve.wait();
lock.lock();
// 从连接池的头部取出一个连接
con = connList.front();
// 同时从连接池中移除该连接
connList.pop_front();
// 更新连接池中的空闲和正在使用的连接数
--m_FreeConn;
++m_CurConn;
lock.unlock();
// 返回获取到的可用连接
return con;
}
6.ReleaseConnection()
释放当前使用的连接
数据库连接池中释放连接的函数。当使用完一个连接后,可以通过调用该函数将该连接释放回连接池,并更新使用和空闲连接数
bool connection_pool::ReleaseConnection(MYSQL *con)
{
// 检查传入的参数con是否为空指针,如果是则直接返回false表示释放失败
if (NULL == con)
return false;
lock.lock();
// 将连接con添加到连接池的尾部
connList.push_back(con);
// 更新连接池中的空闲和正在使用的连接数
++m_FreeConn;
--m_CurConn;
lock.unlock();
// 调用reserve.post()方法,这个方法会通知之前被阻塞的线程,告诉它们当前有可用连接了,以便它们能够从连接池中获取连接
reserve.post();
return true;
}
7.GetFreeConn()
返回当前空闲的连接数
数据库连接池中获取当前空闲连接数的函数。它直接返回连接池对象中的m_FreeConn成员变量,该变量记录了当前连接池中的空闲连接数量
int connection_pool::GetFreeConn()
{
return this->m_FreeConn;
}
8.DestroyPool()
销毁数据库连接池
数据库连接池中销毁连接池的函数。当不再需要使用连接池时,可以通过调用该函数来销毁连接池,并释放已分配的资源
void connection_pool::DestroyPool()
{
lock.lock();
// 检查连接池中是否还有连接
if (connList.size() > 0)
{
list<MYSQL *>::iterator it;
// 遍历所有连接并调用mysql_close()方法关闭连接,释放资源
for (it = connList.begin(); it != connList.end(); ++it)
{
MYSQL *con = *it;
mysql_close(con);
}
// 将连接池中的m_CurConn和m_FreeConn成员变量都置为0,表示当前没有任何连接在使用或者空闲
m_CurConn = 0;
m_FreeConn = 0;
// 调用connList.clear()方法清空连接池中的连接列表
connList.clear();
}
lock.unlock();
}
--------
1.引入库
代码如下(示例):
2.读入数据
代码如下(示例):
data = pd.read_csv(
'https://labfile.oss.aliyuncs.com/courses/1283/adult.data.csv')
print(data.head())
该处使用的url网络请求的数据。
总结
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。