前言

此博客记录对于TinyWebServer项目的学习,并根据自己的理解做出些许更改。
原项目地址:https://github.com/qinguoyi/TinyWebServer

mysql模块逻辑:单例模式,RAII机制

使用以空间换时间的思想,使用连接池的模式初始化多个mysql连接,采用单例懒汉模式创建连接池,使用信号量表示空闲连接数,管理连接出池入池,并且在入池出池操作前加锁,避免操作冲突。
使用RAII机制,将外部获取连接封装到类connectionRAII中,在该类的构造函数中获取连接池中的连接,并将外部MYSQL连接指向该连接,在该类的析构函数中释放该连接,并将其入池。这样使用,当该对象声明结束时,编译器会自动调用其析构函数,回收该连接,避免手动释放。

RAII

Resource Acquisition Is Initialization,c++的一种资源管理机制
将资源调用封装为类的形式,在析构函数中释放资源,当对象生命结束时,系统会自动调用析构函数
在本部分内容中通过connectionRAII类改变外部MYSQL指针使其指向连接池的连接,析构函数归还连接入池。

代码实现

头文件

#ifndef _CONNECTION_POOL_
#define _CONNECTION_POOL_#include <stdio.h>
#include <list>
#include <mysql/mysql.h>
#include <error.h>
#include <string.h>
#include <iostream>
#include <string>
#include "../locker/locker.h"
#include "../log/log.h"using namespace std;class connection_pool
{
public:MYSQL *GetConnection();               //获取数据库连接bool ReleaseConnection(MYSQL *conn); //释放连接int GetFreeConn();                  //获取连接void DestroyPool();                   //销毁所有连接//单例模式 局部静态变量懒汉模式//(C++11之前,多线程不友好)对于多线程而言,多个线程可能同时访问到该静态变量,并发现其没有被初始化(C++实现机制是)//(该看静态变量内部一标志位是为1,为1则说明已被初始化)//多个线程同时判定其没有初始化而后均初始化就会造成错误(即它不是一个原子操作)//C++11之后局部静态变量线程安全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;   //日志开关
};
/********
Resource Acquisition Is Initialization,c++的一种资源管理机制
将资源调用封装为类的形式,在析构函数中释放资源,当对象生命结束时,系统会自动调用析构函数
通过connectionRAII类改变外部MYSQL指针使其指向连接池的连接,析构函数归还连接入池
*********/
class connectionRAII{public:connectionRAII(MYSQL **con, connection_pool *connPool);~connectionRAII();private:MYSQL *conRAII;connection_pool *poolRAII;
};#endif

cpp

#include <mysql/mysql.h>
#include <stdio.h>
#include <string>
#include <string.h>
#include <stdlib.h>
#include <list>
#include <pthread.h>
#include <iostream>
#include "sql_connection_pool.h"using namespace std;connection_pool::connection_pool()
{m_CurConn = 0;m_FreeConn = 0;
}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;for (int i = 0; i < MaxConn; i++){MYSQL *con = NULL;con = mysql_init(con);if (con == NULL){LOG_ERROR("MySQL Error");exit(1);}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.push_back(con);++m_FreeConn;}//使用信号量表示空闲连接数,避免操作冲突reserve = sem(m_FreeConn);m_MaxConn = m_FreeConn;
}//当有请求时,从数据库连接池中返回一个可用连接,更新使用和空闲连接数
MYSQL *connection_pool::GetConnection()
{MYSQL *con = NULL;if (0 == connList.size())return NULL;//信号量reserve为0时会阻塞等待reserve.wait();lock.lock();con = connList.front();connList.pop_front();--m_FreeConn;++m_CurConn;lock.unlock();return con;
}//释放当前使用的连接
bool connection_pool::ReleaseConnection(MYSQL *con)
{if (NULL == con)return false;lock.lock();connList.push_back(con);++m_FreeConn;--m_CurConn;lock.unlock();reserve.post();return true;
}//销毁数据库连接池
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);}m_CurConn = 0;m_FreeConn = 0;connList.clear();}lock.unlock();
}//当前空闲的连接数
int connection_pool::GetFreeConn()
{return this->m_FreeConn;
}connection_pool::~connection_pool()
{DestroyPool();
}
/******* 为什么用二级指针->在函数内改变指针本身时需要使用二级指针,与改变形参的值时需要传递指针或引用是一样的* 编译器会为形参生成一个临时副本,传入指针的指针或者指针的引用才能修改指针本身
*******/
connectionRAII::connectionRAII(MYSQL **SQL, connection_pool *connPool){*SQL = connPool->GetConnection();conRAII = *SQL;poolRAII = connPool;
}connectionRAII::~connectionRAII(){poolRAII->ReleaseConnection(conRAII);
}

功能测试

测试之前确保mysql已安装,并且创建测试使用的库。

#include "sql_connection_pool.h"
#include <unistd.h>void* client_1(void* arg)
{MYSQL* my_con = NULL;connectionRAII conRAII(&my_con, connection_pool::GetInstance());//在user表中检索username,passwd数据,浏览器端输入if (mysql_query(my_con, "SELECT username,passwd FROM user")){printf("SELECT error:%s\n", mysql_error(my_con));}//从表中检索完整的结果集MYSQL_RES *result = mysql_store_result(my_con);//返回结果集中的列数int num_fields = mysql_num_fields(result);//返回所有字段结构的数组MYSQL_FIELD *fields = mysql_fetch_fields(result);sleep(1);//打印用户名和密码while (MYSQL_ROW row = mysql_fetch_row(result)){string temp1(row[0]);string temp2(row[1]);printf("client1->user:%s, pd:%s\n", temp1.c_str(), temp2.c_str());}
}void* client_2(void* arg)
{MYSQL* my_con = NULL;connectionRAII conRAII(&my_con, connection_pool::GetInstance());//在user表中检索username,passwd数据,浏览器端输入if (mysql_query(my_con, "SELECT username,passwd FROM user")){printf("SELECT error:%s\n", mysql_error(my_con));}//从表中检索完整的结果集MYSQL_RES *result = mysql_store_result(my_con);//返回结果集中的列数int num_fields = mysql_num_fields(result);//返回所有字段结构的数组MYSQL_FIELD *fields = mysql_fetch_fields(result);sleep(1);//打印用户名和密码while (MYSQL_ROW row = mysql_fetch_row(result)){string temp1(row[0]);string temp2(row[1]);printf("client2->user:%s, pd:%s\n", temp1.c_str(), temp2.c_str());}}int main()
{connection_pool* con_pool = connection_pool::GetInstance();string url = "localhost";string user = "root";string pd = "ubuntu";string db_name = "db_test";con_pool->init(url, user, pd, db_name, 3306, 2, 0);MYSQL* my_con = NULL;connectionRAII conRAII(&my_con, con_pool);if (mysql_query(my_con, "SELECT username,passwd FROM user")){printf("SELECT error:%s\n", mysql_error(my_con));}//从表中检索完整的结果集MYSQL_RES *result = mysql_store_result(my_con);//返回结果集中的列数int num_fields = mysql_num_fields(result);//返回所有字段结构的数组MYSQL_FIELD *fields = mysql_fetch_fields(result);sleep(1);//打印用户名和密码while (MYSQL_ROW row = mysql_fetch_row(result)){string temp1(row[0]);string temp2(row[1]);printf("main->user:%s, pd:%s\n", temp1.c_str(), temp2.c_str());}pthread_t th1, th2;pthread_create(&th1, NULL, client_1, NULL); sleep(2);pthread_cancel(th1);pthread_create(&th2, NULL, client_2, NULL);sleep(2);pthread_cancel(th2);return 0;
}

main程序初始化了具有两个连接的连接池,main程序使用一个连接,th1线程获取一个连接,然后释放,th2再获取连接。

webserver之mysql模块相关推荐

  1. ELK 经典用法—企业自定义日志收集切割和mysql模块

    ELK 经典用法-企业自定义日志收集切割和mysql模块 一.收集切割公司自定义的日志 很多公司的日志并不是和服务默认的日志格式一致,因此,就需要我们来进行切割了. 1.需切割的日志示例 2018-0 ...

  2. 下载perl的mysql模块_安装用于操作MySQL的Perl模块

    在我使用Webmin(version 1.480)管理FreeBSD主机上的MySQL数据库服务器时出现: "警告:您的系统未安装Perl 模块 DBI 和 DBD::mysql,Webmi ...

  3. mysql_connect() 不支持 请检查 mysql 模块是否正确加载

    在上面文章的基础上配置PHP环境完成之后发现安装(discuz)论坛时候还是有问题! 函数名称                                检查结果          建议 mysq ...

  4. koa mysql模块_koa 项目中引入 mysql

    由于mysql模块的操作都是异步操作,每次操作的结果都是在回调函数中执行,现在有了async/await,就可以用同步的写法去操作数据库 Promise封装mysql模块 Promise封装 ./as ...

  5. Python调用MySQL模块初试

    学Python喊了很长时间了,总是因为各种各样的理由搁置,昨天想起来前同事推荐过一本Python的书<Python核心编程>第二版,就火速买了一本,Python的学习也算是个开始了. 当然 ...

  6. http协议、模块、express框架以及路由器、中间件和mysql模块

    一.http协议 是浏览器和web服务器之间的通信协议 1.通用头信息 request url:请求的url,向服务器请求的数据 request method:请求的方式   get.post sta ...

  7. linux phpinfo mysql_linux服务器 phpinfo 里面找不到 mysql 模块,也没有 pdo_mysql

    linux服务器 phpinfo 里面找不到 mysql 模块,也没有 pdo_mysql linux服务器 phpinfo 里面找不到 mysql 模块,也没有 pdo_mysql 放到服务器上报错 ...

  8. Node中使用mysql模块遇到的问题

    Node的mysql模块,本人的感受就是不好用,各种报错,各种坑,有一个问题困扰了我很久,也不知道是不是我使用的方式不对,不过后来用easymysql模块解决了,我才深信这是一个坑. 问题描述: 假设 ...

  9. saltstack mysql模块_SaltStack工具中MySQL的模块返回值问题解决

    由于管理系统中对mysql管理的开发中用到了saltstack集成的mysql模块其中一个主要的功能是 mysql.query 官方文档中的两个示例: salt.modules.mysql.query ...

最新文章

  1. 9 张图带你深入理解 Docker 架构!
  2. MOCTF-Web-暴跳老板*
  3. SAP UI5 library-dbg.js - local location
  4. UnityShader RenderTypeQueue 渲染顺序
  5. cvRemap 对图像进行普通几何变换
  6. (九)深入浅出TCPIP之网络同步异步
  7. __super作用(C++中)
  8. CentOS6.4下Mysql数据库的安装与配置
  9. java 内置jetty_内置jetty
  10. JIRA状态为任务结束,但是解决结果为未解决相关配置
  11. mysql数据迁移性能_百万级MySQL的数据量,该如何快速的完成数据迁移?
  12. Atitit webservice之道 艾提拉著 目录 1. 基本说明Web Service 1 2. 基本概念与内部构成 2 2.1. Web services要使用两种技术: XML SOAP
  13. 如何安装Ruby(Windows)
  14. 彩虹代刷网用php几,php彩虹代刷网八套模板源码+教程
  15. SPSS图文教程:两个率的比较(卡方检验)及Fisher精确检验
  16. 从武汉远程医疗方案看,5G战“疫”是噱头还是福音?
  17. pyodbc mysql_Robot Framework 通过pyodbc连接Mysql
  18. 【转】java将excel文件转换成txt格式文件
  19. 机器学习:数据归一化(Scaler)
  20. 集团公司申请企业邮箱有哪些注意事项?

热门文章

  1. Linux用户配置文件(第二版)
  2. 通过交互式命令从github拉取项目模板并创建新项目
  3. 常见蓝屏故障及解决办法
  4. 微信小游戏的前端攻城狮玩法
  5. New to My Oracle Support?
  6. 81. Search in Rotated Sorted Array II
  7. 【转】职业生涯30年的规划(经典)
  8. jpa 人大金仓数据库方言_国产数据库的春天,人大金仓完成近亿元融资
  9. 信息学奥赛一本通 1839:【05NOIP提高组】谁拿了最多奖学金 | OpenJudge NOI 1.9 04:谁拿了最多奖学金 | 洛谷 P1051 [NOIP2005 提高组] 谁拿了最多奖学金
  10. 信息学奥赛一本通(1117:整数去重)