Mysql数据库是一个C/S模型,通过客户端来访问服务端。底层使用的是TCP协议。
在连接数据库和断开数据库时,需要进行一下几个步骤:
当在我们在程序中需要频繁的访问数据库,也就是需要频繁的连接数据库和断开数据库时,会需要频繁的进行上面的操作。在高并发的情况下会消耗很多时间和资源。
使用连接池可以减少这部分的消耗。指挥在创建连接池时,建立连接,在销毁连接池对象时,断开连接。需要连接数据库时,在连接池中取出连接,不需要使用数据库时,将连接放会连接池即可。
在网络通信中,服务器可能收到多个客户端的请求。连接池部署在服务器上,并且服务端会部署各种组件,其中数据库组件可能部署在另外一台服务器上,需要操作数据库,就需要连接另外一台服务器。
使用线程池和连接池可以大大的提高效率。
多线程,可以用来处理不用的任务,比如:接受客户端的请求,处理客户端的请求,从连接池中取出连接等。
对于连接池,首先在连接池中,与数据库建立若干个连接,需要使用连接数据库时,从连接池中取,不需要连接时,将连接放入连接池中。
实现的功能点:
细节分析:
释放数据库的资源,需要释放创建数据库的资源和结果集的资源。
使用的C语言MySql接口:用C语言API(常用)操作MySql数据库_两片空白的博客-CSDN博客
- #pragma once
-
-
- #include
- #include
- #include
- 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);
- //更新数据库 update delete insert
- bool update(string sql);
- //查询数据库
- bool query(string sql);
- //遍历数据库,主要是查找结果集中的下一行数据
- bool next();
- //得到结果集中需要行的index列的字段
- string value(int index);
- //事务操作
- bool transaction();
- //提交事务
- bool commit();
- //事务回滚
- bool roolback();
- //刷新连接等待时间
- void refreshAliveTime();
- //获得连接等待时间
- long long getAliveTime();
- private:
- //释放结果集的资源
- void releaseRes();
-
- MYSQL* m_conn = nullptr;
- MYSQL_RES* m_res = nullptr;
- MYSQL_ROW m_row = nullptr;
- steady_clock::time_point m_aliveTime;
-
- };
- #include "MysqlConn.h"
-
- MysqlConn::MysqlConn()
- {
- m_conn = mysql_init(nullptr);
- }
-
- MysqlConn::~MysqlConn()
- {
- if (m_conn)
- {
- mysql_close(m_conn);
- }
- releaseRes();
- }
-
- 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);
- if (ptr)
- {
- return true;
- }
- return false;
- }
-
- bool MysqlConn::update(string sql)
- {
- if (mysql_query(m_conn, sql.c_str()))
- {
- return false;
- }
- return true;
- }
-
- bool MysqlConn::query(string sql)
- {
- //在查询结果集时,需要清空上一次结果集的内存
- releaseRes();
- if (mysql_query(m_conn, sql.c_str()) == 0)
- {
- m_res = mysql_store_result(m_conn);
- return true;
- }
- return false;
- }
-
- bool MysqlConn::next()
- {
- if (m_res != nullptr)
- {
- m_row = mysql_fetch_row(m_res);
- if (m_row)
- {
- return true;
- }
- }
- return false;
- }
-
- //参数时这一行的第几列
- string MysqlConn::value(int index)
- {
- //得到当前行中,列的数量
- int resNum = mysql_num_fields(m_res);
- if (index < 0 || index >= resNum)
- {
- return string();
- }
-
- char* str = m_row[index];
- unsigned long length = mysql_fetch_lengths(m_res)[index];//获得index列字段的长度
- return string(str, length);
- }
-
- bool MysqlConn::transaction()
- {
- return mysql_autocommit(m_conn, false);
- }
-
- bool MysqlConn::commit()
- {
- return mysql_commit(m_conn);
- }
-
- bool MysqlConn::roolback()
- {
- 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
(res); - return millsec.count();
- }
-
- void MysqlConn::releaseRes()
- {
- if (m_res)
- {
- mysql_free_result(m_res);
- }
- }
- #pragma once
-
- #include "MysqlConn.h"
- #include
- #include
- #include
-
- class ConnectionPool
- {
- public:
- ConnectionPool* getConnectionPool();
- ConnectionPool(const ConnectionPool& pool) = delete;
- ConnectionPool& operator=(const ConnectionPool& pool) = delete;
- shared_ptr
getConnection() ; - private:
- ConnectionPool();
- ~ConnectionPool();
- bool parseJsonFile();
- void productConnection();
- void recycleConnection();
- void addConnection();
-
- string m_ip;
- string m_userName;
- string m_passwd;
- string m_dbName;
- unsigned short m_port;
-
- int m_maxSize;//最大使用连接数
- int m_minSize;//连接池中最少连接数
- int m_timeout;
- int m_maxIdleTime;
- int m_useCount;//使用的连接数
- queue
m_pool; - mutex m_lock;
- condition_variable m_cond;
- };
- #include "ConnectionPool.h"
- #include
- #include
- #include
-
- using namespace Json;
- ConnectionPool::ConnectionPool()
- {
- //读取配置
- if (!parseJsonFile())
- {
- return;
- }
-
- //生成连接
- for (int i = 0; i < m_minSize; ++i)
- {
- addConnection();
- }
-
- //判断连接个数,是否需要创建连接或者销毁连接
- //单独用两个线程处理,处理的是连接池中的连接数
- thread produtor(&ConnectionPool::productConnection, this);
- thread recyclor(&ConnectionPool::recycleConnection, this);
- produtor.detach();
- recyclor.detach();
- }
-
- ConnectionPool::~ConnectionPool()
- {
- while (!m_pool.empty())
- {
- MysqlConn* conn = m_pool.front();
- m_pool.pop();
- delete conn;
- }
- }
-
- ConnectionPool* ConnectionPool::getConnectionPool()
- {
- static ConnectionPool pool;
- return &pool;
- }
-
- bool ConnectionPool::parseJsonFile()
- {
- ifstream ifs("dbConfig.json");
- Reader rd;
- Value root;
- rd.parse(ifs, root);
- if (root.isObject())
- {
- m_ip = root["ip"].asString();
- m_port = root["port"].asInt();
- m_userName = root["userName"].asString();
- m_passwd = root["passwd"].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::productConnection()
- {
- while (true)
- {
- //对整个局域加锁
- unique_lock
locker(m_lock) ; - while (m_pool.size() >= m_minSize)
- {
- m_cond.wait(locker);
- }
- addConnection();
- //唤醒消费者,生产者只有一个线程,就是当前线程
- m_cond.notify_all();
- }
- }
-
- //当连接池的连接个数大于minSize并且等待时长大于最大等待时间,需要销毁
- void ConnectionPool::recycleConnection()
- {
- while (true)
- {
- this_thread::sleep_for(milliseconds(500));
- lock_guard
locker(m_lock) ; - while (m_pool.size() > m_minSize)
- {
- MysqlConn* conn = m_pool.front();
- if (conn->getAliveTime() >= m_maxIdleTime)
- {
- //加锁
- m_pool.pop();
- delete conn;
- conn = nullptr;
- }
- else
- {
- break;
- }
- }
- }
- }
-
- void ConnectionPool::addConnection()
- {
- MysqlConn* conn = new MysqlConn;
- conn->connect(m_userName, m_passwd, m_dbName, m_ip, m_port);
- conn->refreshAliveTime();
- m_pool.push(conn);
- }
-
- shared_ptr
ConnectionPool::getConnection() - {
- //加锁
- unique_lock
locker(m_lock) ; - while (m_pool.empty() || m_useCount >= m_maxSize)
- {
- //等待一段时间
- if (cv_status::no_timeout == m_cond.wait_for(locker, milliseconds(m_timeout)))
- {
- //一段时间内没有被唤醒
- if (m_pool.empty() || m_useCount >= m_maxSize)
- {
- continue;
- }
- }
- }
- //从连接池中取连接
- shared_ptr
conn(m_pool.front(), [this](MysqlConn* conn) { - //删除器,将连接放回连接池
- lock_guard
lock(m_lock); - conn->refreshAliveTime();
- m_pool.push(conn);
- m_useCount--;
- m_cond.notify_all();
- });
-
- //lock_guard
lock(m_lock);上面加了 - m_pool.pop();
- m_useCount++;
- //唤醒生产者,由于生产者和消费者使用的同一个环境变量,会将消费者也唤醒
- //但是不影响,会继续判断
- m_cond.notify_all();
- return conn;
- }
- #include
- #include "MysqlConn.h"
- #include "ConnectionPool.h"
-
- //测试数据库API
- void query()
- {
- MysqlConn conn;
- conn.connect("root", "Root_123", "testdb", "114.55.92.82", 3306);
- string sql = "insert into person value(2, 20, \"man\", \"jj\")";
- conn.query(sql);
-
- sql = "select * from person";
- bool flag = conn.query(sql);
- cout << "flag value" << flag << endl;
-
- while (conn.next())
- {
- cout << conn.value(0) << ","
- << conn.value(1) << ","
- << conn.value(2) << ","
- << conn.value(3) << ","
- << endl;
- }
- }
-
- void op1(int begin, int end)
- {
- for (int i = begin; i < end; ++i)
- {
- MysqlConn conn;
- conn.connect("root", "Root_123", "testdb", "114.55.92.82", 3306);
- //string sql;
- char sql[1024] = { 0 };
- sprintf(sql, "insert into person value(%d, 20, \"man\", \"jj\")", i);
- conn.update(sql);
- }
- }
-
- void op2(ConnectionPool* pool, int begin, int end)
- {
- for (int i = begin; i < end; ++i)
- {
- shared_ptr
ptr = pool->getConnection(); - char sql[1024] = {0};
- sprintf(sql, "insert into person value(%d, 20, \"man\", \"jj\")", i);
- ptr->update(sql);
- }
- }
-
- //单线程
- void test1()
- {
- #if 1
- //非连接池 单线程 耗时108848850600纳秒 108848毫秒
- steady_clock::time_point begin = steady_clock::now();
- op1(0, 1000);
- steady_clock::time_point end = steady_clock::now();
- auto length = end - begin;
- cout << "非连接池 单线程 耗时" << length.count() << "纳秒 "
- << length.count() / 1000000 << "毫秒" << endl;
- #else
- //连接池 单线程 耗时16893997100纳秒 16893毫秒
- ConnectionPool* pool = ConnectionPool::getConnectionPool();
- steady_clock::time_point begin = steady_clock::now();
- op2(pool, 0, 1000);
- steady_clock::time_point end = steady_clock::now();
- auto length = end - begin;
- cout << "连接池 单线程 耗时" << length.count() << "纳秒 "
- << length.count() / 1000000 << "毫秒" << endl;
- #endif
- }
-
- void test2()
- {
- #if 0
- //非连接池 多线程 耗时20575826400纳秒 20575毫秒
-
- //如果同一时间多个线程连接数据库,会导致一些线程连接失败
- MysqlConn conn;
- conn.connect("root", "Root_123", "testdb", "114.55.92.82", 3306);
-
- steady_clock::time_point begin = steady_clock::now();
- thread t1(op1, 0, 200);
- thread t2(op1, 200, 400);
- thread t3(op1, 400, 600);
- thread t4(op1, 600, 800);
- thread t5(op1, 800, 1000);
- t1.join();
- t2.join();
- t3.join();
- t4.join();
- t5.join();
- steady_clock::time_point end = steady_clock::now();
- auto length = end - begin;
- cout << "非连接池 多线程 耗时" << length.count() << "纳秒 "
- << length.count() / 1000000 << "毫秒" << endl;
- #else
- //连接池 多线程 耗时4014272600纳秒 4014毫秒
- ConnectionPool* pool = ConnectionPool::getConnectionPool();
- steady_clock::time_point begin = steady_clock::now();
- thread t1(op2, pool, 0, 200);
- thread t2(op2, pool, 200, 400);
- thread t3(op2, pool, 400, 600);
- thread t4(op2, pool, 600, 800);
- thread t5(op2, pool, 800, 1000);
- t1.join();
- t2.join();
- t3.join();
- t4.join();
- t5.join();
- steady_clock::time_point end = steady_clock::now();
- auto length = end - begin;
- cout << "连接池 多线程 耗时" << length.count() << "纳秒 "
- << length.count() / 1000000 << "毫秒" << endl;
- #endif
- }
-
-
- int main()
- {
- test2();
- return 0;
- }
当前项目中会需要使用mysql和jsoncpp
找到对应动态库,将对应动态库加到项目对应exe文件下。
找到下载的mysql代码,在bin目录下,找到对应库文件,拷贝到项目的对应exe文件下