好的,TinyWebServer我们讲了八个模块中的5个,还剩下数据库mysql模块,定时器timer模块,日记log模块。
(更新中~~~~~~)
mysql模块
项目中有简单的注册和登录功能,所以要使用到数据库。那么mysql模块就是数据库相关的模块,主要的其实就是数据库连接池。
首先数据库连接池是只有一个的,那么怎么保证从项目的每一个地方获取都是这个唯一的一个数据库连接池呢?欸,想到什么了?单例模式。在这里我们使用Cpp11下简洁的静态局部变量实现单例模式:
connection_pool* connection_pool::GetInstance() {
static connection_pool connPool;
return &connPool;
}
原理是是C++11标准规定了当一个线程正在初始化一个变量的时候,其他线程必须得等到该初始化完成以后才能访问它。
OK我们上面解决了池子的问题,接下来我们考虑到,WebServer要有一定的并发度,所以我们要有多个数据库连接资源放在数据库连接池,当任务线程需要数据库连接的时候就向池子申请一个。好的,那么我们便有了一个问题:怎样保证数据库连接的线程安全?
我们先得有一个保存数据库连接的数据结构list,当然我们得先保证池子(或者说list的安全)的线程安全,所以有一个池子的互斥锁lock,然后我们保证list中连接资源的安全,所以再有一个信号量reserve,用于管理池子的空闲连接数。
有了这两个池子接下来的就是比较常规的做法了:在获取/归还数据库连接资源前先用互斥锁对池子加锁,然后用信号量保证list空闲连接资源数。
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7
8 #include"sql_connection_pool.h"
9
10 using namespacestd;11
12 //构造函数
13 connection_pool::connection_pool() {14 this->CurConn = 0;15 this->FreeConn = 0;16 this->MaxConn = 0;17 }18
19 //单例模式,静态
20 connection_pool*connection_pool::GetInstance() {21 staticconnection_pool connPool;22 return &connPool;23 }24
25 //真正的初始化函数
26 void connection_pool::init(string url, string User, string PassWord, string DBName, int Port, unsigned intMaxConn) {27 this->url =url;28 this->Port =Port;29 this->User =User;30 this->PassWord =PassWord;31 this->DatabaseName =DBName;32
33 //先互斥锁锁住池子,创造MaxConn数据库链接
34 lock.lock();35 for (int i = 0; i < MaxConn; i++) {36 //新创建一个连接资源
37 MYSQL* con =NULL;38 con =mysql_init(con);39
40 if (con ==NULL) {41 cout << "mysqlinit Error:" << mysql_error(con)<
45 con = mysql_real_connect(con, url.c_str(), User.c_str(), PassWord.c_str(), DBName.c_str(), Port, NULL, 0);46 if (con ==NULL) {47 cout << "mysql connect Error:" << mysql_error(con) <
51 //把这个资源放入链表
52 connList.push_back(con);53 ++FreeConn;54 }55
56 //初始化信号量和池子数量
57 reserve =sem(FreeConn);58 this->MaxConn =FreeConn;59
60 lock.unlock();61 }62
63 //请求获取一个连接资源
64 MYSQL*connection_pool::GetConnection() {65 MYSQL* con =NULL;66
67 if (connList.size() == 0) returnNULL;68
69 //请求一个资源,互斥锁/信号量 准备
70 reserve.wait();71 lock.lock();72
73 con = connList.front(); //从链表头取得一个资源
74 connList.pop_front();75
76 --FreeConn;77 ++CurConn;78
79 lock.unlock();80 returncon;81 }82
83 //获取空闲连接数
84 intconnection_pool::GetFreeConn() {85 return this->FreeConn;86 }87
88 //释放当前连接资源con
89 bool connection_pool::ReleaseConnection(MYSQL*con) {90 if (con == NULL) return false;91 lock.lock();92
93 connList.push_back(con);94 ++FreeConn;95 --CurConn;96
97 reserve.post();98 lock.unlock();99
100 return true;101 }102
103 //析构函数
104 connection_pool::~conne