赞
踩
对于数据库操作都是在访问数据库的时候创建连接,访问完毕断开连接。但是如果在高并发情况下,有些需要频繁处理的操作就会消耗很多的资源和时间,比如:
数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个。在并发程度比较高的时候,连接池技术尽可能多地重用了消耗内存地资源,大大节省了内存,提高了服务器地服务效率,能够支持更多的客户服务。通过使用连接池,将大大提高程序运行效率。
数据库连接顺序
数据库连接池
数据库连接服务操作模块:
#pragma once #include <iostream> #include <mysql.h> #include <chrono> using namespace std; using namespace chrono; class MysqlConn { public: // 初始化数据库连接 MysqlConn(); // 释放数据库连接 ~MysqlConn(); // 连接数据库 bool connect(string user, string passwd, string dbName, string ip, unsigned short port = 3306); // 更新数据库: insert, update, delete bool update(string sql); // 查询数据库 bool query(string sql); // 遍历查询得到的结果集 bool next(); // 得到结果集中的字段值 string value(int index); // 事务操作 bool transaction(); // 提交事务 bool commit(); // 事务回滚 bool rollback(); // 刷新起始的空闲时间点 void refreshAliveTime(); // 计算连接存活的总时长 long long getAliveTime(); private: void freeResult(); MYSQL* m_conn = nullptr; MYSQL_RES* m_result = nullptr; MYSQL_ROW m_row = nullptr; steady_clock::time_point m_alivetime;// 绝对时钟判断连接存活时长 };
#include "MysqlConn.h" MysqlConn::MysqlConn() { m_conn = mysql_init(nullptr); //初始化对象 mysql_set_character_set(m_conn, "utf8"); // 设置utf-8编码格式 } MysqlConn::~MysqlConn() { if (m_conn != nullptr) { mysql_close(m_conn); //关闭连接 } freeResult(); // 释放一个结果集合使用的内存。 } bool MysqlConn::connect(string user, string passwd, string dbName, string ip, unsigned short port) { MYSQL* ptr = mysql_real_connect(m_conn, ip.c_str(), user.c_str(), passwd.c_str(), dbName.c_str(), port, nullptr, 0); //连接mysql服务器 return ptr != nullptr; } bool MysqlConn::update(string sql) { if (mysql_query(m_conn, sql.c_str())) //更新数据库 { return false; } return true; } bool MysqlConn::query(string sql) { freeResult(); if (mysql_query(m_conn, sql.c_str())) { return false; } m_result = mysql_store_result(m_conn); // 保存结果集 return true; } bool MysqlConn::next() { if (m_result != nullptr) { m_row = mysql_fetch_row(m_result); if (m_row != nullptr) { return true; } } return false; } string MysqlConn::value(int index) { int rowCount = mysql_num_fields(m_result); if (index >= rowCount || index < 0) { return string(); } char* val = m_row[index]; unsigned long length = mysql_fetch_lengths(m_result)[index]; return string(val, length); } bool MysqlConn::transaction() { return mysql_autocommit(m_conn, false); //手动提交,不自动提交事务。 } bool MysqlConn::commit() { return mysql_commit(m_conn); //提交事务 } bool MysqlConn::rollback() { return mysql_rollback(m_conn); // 事务回滚 } void MysqlConn::refreshAliveTime() { m_alivetime = steady_clock::now(); } long long MysqlConn::getAliveTime() { nanoseconds res = steady_clock::now() - m_alivetime;// 纳秒 较高精度 milliseconds millsec = duration_cast<milliseconds>(res);// 毫秒 精度相对较低 return millsec.count(); } void MysqlConn::freeResult() { if (m_result) { mysql_free_result(m_result); m_result = nullptr; } }
连接池
#pragma once #include <queue> #include <mutex> #include <condition_variable> #include "MysqlConn.h" using namespace std; class ConnectionPool { public: static ConnectionPool* getConnectPool(); // 创建单例模式 ConnectionPool(const ConnectionPool& obj) = delete; //禁止使用拷贝构造 ConnectionPool& operator=(const ConnectionPool& obj) = delete; // 禁止使用拷贝赋值运算符 shared_ptr<MysqlConn> getConnection(); ~ConnectionPool(); private: ConnectionPool(); //构造函数设置为私有的,单例模式 bool parseJsonFile(); void produceConnection(); void recycleConnection(); void addConnection(); string m_ip;// 数据库服务器ip地址 string m_user;// 数据库服务器用户名 string m_passwd;// 数据库服务器密码 string m_dbName;// 数据库服务器的数据库名 unsigned short m_port;// 数据库服务器绑定的端口 int m_minSize;// 连接池维护的最小连接数 int m_maxSize;// 连接池维护的最大连接数 int m_timeout;// 连接池获取连接的超时时长 int m_maxIdleTime;// 连接池中连接的最大空闲时长 queue<MysqlConn*> m_connectionQ; // 连接队列 mutex m_mutexQ; condition_variable m_cond; };
#include "ConnectionPool.h" #include <json/json.h> #include <fstream> #include <thread> using namespace Json; ConnectionPool* ConnectionPool::getConnectPool() { static ConnectionPool pool; return &pool; } bool ConnectionPool::parseJsonFile() { ifstream ifs("dbconf.json"); Reader rd; Value root; rd.parse(ifs, root); if (root.isObject()) { m_ip = root["ip"].asString(); m_port = root["port"].asInt(); m_user = root["userName"].asString(); m_passwd = root["password"].asString(); m_dbName = root["dbName"].asString(); m_minSize = root["minSize"].asInt(); m_maxSize = root["maxSize"].asInt(); m_maxIdleTime = root["maxIdleTime"].asInt(); m_timeout = root["timeout"].asInt(); return true; } return false; } // 生产连接线程函数 void ConnectionPool::produceConnection() { while (true) { unique_lock<mutex> locker(m_mutexQ); // 锁 while (m_connectionQ.size() >= m_minSize) { m_cond.wait(locker); // 条件变量 } addConnection(); // 执行连接 m_cond.notify_all(); // 通知消费者线程消费 } } // 销毁连接 void ConnectionPool::recycleConnection() { while (true) { this_thread::sleep_for(chrono::milliseconds(500)); lock_guard<mutex> locker(m_mutexQ); while (m_connectionQ.size() > m_minSize) { MysqlConn* conn = m_connectionQ.front(); if (conn->getAliveTime() >= m_maxIdleTime) // 判断连接存活时长,如果满足条件就行删除 { m_connectionQ.pop(); delete conn; } else { break; } } } } void ConnectionPool::addConnection() { MysqlConn* conn = new MysqlConn; conn->connect(m_user, m_passwd, m_dbName, m_ip, m_port); conn->refreshAliveTime(); m_connectionQ.push(conn); } // 取出可用连接 shared_ptr<MysqlConn> ConnectionPool::getConnection() { unique_lock<mutex> locker(m_mutexQ); while (m_connectionQ.empty()) // 判断连接是否为空 { if (cv_status::timeout == m_cond.wait_for(locker, chrono::milliseconds(m_timeout)))// 阻塞一段时间 { if (m_connectionQ.empty()) { //return nullptr; continue; } } } // lambda表达式定义shared_ptr的销毁函数。 shared_ptr<MysqlConn> connptr(m_connectionQ.front(), [this](MysqlConn* conn) { lock_guard<mutex> locker(m_mutexQ); conn->refreshAliveTime(); m_connectionQ.push(conn); }); m_connectionQ.pop(); m_cond.notify_all();// 唤醒生产者线程,附带着也会唤醒消费者线程 return connptr; } ConnectionPool::~ConnectionPool() { while (!m_connectionQ.empty()) { MysqlConn* conn = m_connectionQ.front(); m_connectionQ.pop(); delete conn; } } ConnectionPool::ConnectionPool() { // 加载配置文件 if (!parseJsonFile()) { return; } for (int i = 0; i < m_minSize; ++i) // 默认情况保证有minsize个数的连接就行了。 { addConnection(); } thread producer(&ConnectionPool::produceConnection, this);// 生产连接 thread recycler(&ConnectionPool::recycleConnection, this);// 看有没有需要销毁的连接 producer.detach(); recycler.detach(); }
参考列表:
https://www.bilibili.com/video/BV1Fr4y1s7w4
https://blog.csdn.net/CrankZ/article/details/82874158
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。