大略的说:创建数据库连接是一个很耗时的操作,也随意马虎对数据库造成安全隐患。以是,在程序初始化的时候,集中创建多个数据库连接,并把他们集中管理,供程序利用,可以担保较快的数据库读写速率,还更加安全可靠。
二、图示不该用数据库连接池
如果不该用数据库连接池,对付每一次SQL操作,都要走一遍下面完全的流程:

1.TCP建立连接的三次握手(客户端与 MySQL做事器的连接基于TCP协议)
2.MySQL认证的三次我收
3.真正的SQL实行
4.MySQL的关闭
5.TCP的四次握手关闭
可以看出来,为了实行一条SQL,须要进行大量的初始化与关闭操作
利用数据库连接池
如果利用数据库连接池,那么会事先申请(初始化)好干系的数据库连接,然后在之后的SQL操作中会复用这些数据库连接,操作结束之后数据库也不会断开连接,而是将数据库工具放回到数据库连接池中
三、数据库连接池的好处
资源重用:由于数据库连接得到重用,避免了频繁的创建、开释连接引起的性能开销,在减少系统花费的根本上,另一方面也匆匆进了系统运行环境的平稳性(减少内存碎片以及数据库临时进程/线程的数量)。
更快的系统相应速率:数据库连接池在初始化过程中,每每已经创建了多少数据库连接置于池中备用。 此时连接的初始化事情均已完成。对付业务要求处理而言,直策应用现有可用连接,避免了从数据库连接初始化和开释过程的开销,从而缩减了系统整体相应韶光。
统一的连接管理,避免数据库连接透露:在较为完备的数据库连接池实现中,可根据预先的连接占用超时设定,逼迫收回被占用连接。从而避免了常规数据库连接操作中可能涌现的资源透露。
四、连接池数量设置连接数 = ((核心数 2) + 有效磁盘数)
如果说你的做事器CPU是4核i7的,连接池大小该当为((42)+1)=9
干系视频推举
90分钟搞懂数据库连接池技能|linux后台开拓
《tcp/ip详解卷一》: 150行代码拉开协议栈实现的篇章
学习地址:C/C++Linux做事器开拓/后台架构师【零声教诲】-学习视频教程-腾讯教室
须要C/C++ Linux做事器架构师学习资料加qun812855908获取(资料包括C/C++,Linux,golang技能,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享
五、MySQL连接池演示
源码下载
下载办法:https://github.com/dongyusheng/csdn-code/tree/master/db_pool(Github中下载)
db_pool目录下有两个目录,mysql_pool目录为MySQL连接池代码,redis_pool为redis连接池代码
下面先容mysql_pool
CDBConn解析
class CDBConn {public:// ...private:CDBPool m_pDBPool;// to get MySQL server informationMYSQL m_mysql;// 对应一个连接charm_escape_string[MAX_ESCAPE_STRING_LEN + 1];};
观点:代表一个数据连接工具实例
干系成员:
m_pDBPool:该数据库连接工具所属的数据库连接池
布局函数:绑定自己所属于哪个数据库连接池
CDBConn::CDBConn(CDBPool pPool){m_pDBPool = pPool;m_mysql = NULL;}
Init()函数:创建数据库连接句柄
int CDBConn::Init(){m_mysql = mysql_init(NULL);if (!m_mysql){log_error("mysql_init failed\n");return 1;} my_bool reconnect = true;mysql_options(m_mysql, MYSQL_OPT_RECONNECT, &reconnect);// 合营mysql_ping实现自动重连mysql_options(m_mysql, MYSQL_SET_CHARSET_NAME, "utf8mb4"); if (!mysql_real_connect(m_mysql, m_pDBPool->GetDBServerIP(), m_pDBPool->GetUsername(), m_pDBPool->GetPasswrod(),m_pDBPool->GetDBName(), m_pDBPool->GetDBServerPort(), NULL, 0)){log_error("mysql_real_connect failed: %s\n", mysql_error(m_mysql));return 2;} return 0;}
CDBPool解析
class CDBPool {public:// ...private:string m_pool_name;// 连接池名称string m_db_server_ip;// 数据库ipuint16_tm_db_server_port; // 数据库端口string m_username; // 用户名string m_password;// 用户密码string m_db_name;// db名称intm_db_cur_conn_cnt;// 当前启用的连接数量int m_db_max_conn_cnt;// 最大连接数量list<CDBConn>m_free_list;// 空闲的连接CThreadNotifym_free_notify;// 旗子暗记量};
观点:代表一个数据库连接池
干系成员:
m_db_cur_conn_cnt:当前数据库连接池的连接数量m_db_max_conn_cnt:数据库连接池支持的最大连接数量(m_db_cur_conn_cnt<=m_db_max_conn_cnt)m_free_list:存放空闲数据库连接工具的(可以从这里取出数据库连接工具利用)Init()函数:常见指天命量的数据库实例句柄,然后添加到m_free_list中,供后面利用
int CDBPool::Init(){// 创建固定最小的连接数量for (int i = 0; i < m_db_cur_conn_cnt; i++){CDBConn pDBConn = new CDBConn(this);int ret = pDBConn->Init();if (ret){delete pDBConn;return ret;} m_free_list.push_back(pDBConn);} // log_error("db pool: %s, size: %d\n", m_pool_name.c_str(), (int)m_free_list.size());return 0;}
GetDBConn()函数:用于从空闲行列步队中返回可以利用的数据库连接句柄
/ TODO: 增加保护机制,把分配的连接加入另一个行列步队,这样获取连接时,如果没有空闲连接, TODO: 检讨已经分配的连接多久没有返回,如果超过一定韶光,则自动收回连接,放在用户忘了调用开释连接的接口 /CDBConn CDBPool::GetDBConn(){m_free_notify.Lock(); while (m_free_list.empty()){// m_db_cur_conn_cnt是统共多少个连接,不是指空闲的if (m_db_cur_conn_cnt >= m_db_max_conn_cnt){m_free_notify.Wait();}else{CDBConn pDBConn = new CDBConn(this);int ret = pDBConn->Init();if (ret){log_error("Init DBConnecton failed\n\n");delete pDBConn;m_free_notify.Unlock();return NULL;}else{m_free_list.push_back(pDBConn);m_db_cur_conn_cnt++;log("new db connection: %s, conn_cnt: %d\n", m_pool_name.c_str(), m_db_cur_conn_cnt);}}} CDBConn pConn = m_free_list.front();// 获取连接m_free_list.pop_front();// STL 吐出连接,从空闲行列步队删除 m_free_notify.Unlock(); return pConn;}
RelDBConn()函数:程序利用完该数据库句柄之后,将句柄放回到空闲行列步队中
void CDBPool::RelDBConn(CDBConn pConn){m_free_notify.Lock(); list<CDBConn >::iterator it = m_free_list.begin();for (; it != m_free_list.end(); it++){if (it == pConn){break;}} if (it == m_free_list.end())
测试
测试之前,将代码中的数据库地址、端口、账号密码等改为自己的(代码中有好几处)
进入MySQL,创建mysql_pool_test数据库
CREATE DATABASE mysql_pool_test;
进入到mysql_pool目录下,创建一个build目录并进入:
mkdir buildcd build
然后输入如下的命令进行编译
cmake ..make
之后就会在目录下天生如下的可实行文件
输入如下两条命令进行测试:可以看到不该用数据库连接池,全体操作耗时4秒旁边;利用连接池之后,全体操作耗时2秒旁边,提升了一倍
# 不该用数据库连接池./test_ThreadPool 4 4 0# 利用数据库连接池./test_ThreadPool 4 4 1
源码下载
下载办法:https://github.com/dongyusheng/csdn-code/tree/master/db_pool(Github中下载)下面先容redis_pool
测试
进入到redis_pool目录下,创建一个build目录并进入:
mkdir buildcd build
然后输入如下的命令进行编译
cmake ..make
之后就会在目录下天生如下的可实行文件
输入如下的命令进行测试:可以看到不该用数据库连接池,全体操作耗时182ms;利用连接池之后,全体操作耗时21ms,提升了很多
# 不该用数据库连接池./test_ThreadPool 4 4 0# 利用数据库连接池./test_ThreadPool 4 4 1
进入redis,可以看到我们新建的key: