当前位置:网站首页>Database connection pool: Code Directory

Database connection pool: Code Directory

2022-06-22 15:05:00 _ Soren

Preface

of MySQL Database programming 、 Multithreaded programming 、 Thread mutual exclusion and synchronous communication operation 、 Intelligent pointer 、 Design patterns 、 Containers, etc. these technologies are C++ Language level can be realized directly , Therefore, the project is selected directly in windows On the platform 【virtual studio 2022】 Development .

The header file

public.h

#pragma once
#include<iostream>

#define LOG(str) \ std::cout << __FILE__ << ":" << __LINE__ << " " << \ __TIMESTAMP__ << " : " << str << std::endl;

Connection.h

//  Realization MySQL Operation of database 
#include <mysql.h>
#include <string>
#include <ctime>
using namespace std;

//  Database operation class 
class Connection
{
    
public:
	//  Initialize database connection 
	Connection();

	//  Release database connection resources 
	~Connection();

	//  Connect to database 
	bool connect(string ip,
		unsigned short port,
		string user, 
		string password,
		string dbname);

	//  update operation  insert、delete、update
	bool update(string sql);

	//  Query operation  select
	MYSQL_RES* query(string sql);

	//  Refresh the starting idle time of the connection 
	void refreshAliveTime();

	//  Return to the time of survival 
	clock_t getAliveTime() const;

private:
	MYSQL* _conn;		//  Represents and MySQL Server A connection of 
	clock_t _aliveTime; //  Record the survival time after entering the idle state 
};

CommonConnectionPool.h

#pragma once
//  Implement the connection pool function module 
#include<iostream>
#include<string>
#include<queue>
#include<mutex>
#include<atomic>
#include<thread>
#include<memory>
#include<functional>
#include<condition_variable>
#include "Connection.h"

using namespace std;

class ConnectionPool
{
    
public:
	//  Get connection pool object instance   Static 
	static ConnectionPool* getConnectionPool();

	//  Provide an interface to the outside , Provide an idle connection 
	shared_ptr<Connection> getConnection();

private:
	ConnectionPool(); //  The singleton pattern   Constructor privatization 

	bool loadConfigFile(); //  Load profile 

	//  Producer thread function ,  Responsible for the production of new connections 
	void produceConnectionTask();

	//  Recycling thread functions , Responsible for recycling redundant idle connections 
	void scannerConnectionTask();

	string _ip;				// MySQL Of IP Address 
	unsigned short _port;	// MySQL Port number 
	string _username;		// MySQL Login user name of 
	string _password;		// MySQL Login password for 
	string _dbname;			//  Database name 
	int _initSize;			//  The initial number of connections to the connection pool 
	int _maxSize;			//  The maximum number of connections in the connection pool 
	int _maxIdleTime;		//  The maximum waiting time of the connection pool 
	int _connectionTimeOut;	//  The timeout for the connection pool to obtain connections 

	queue<Connection*> _connectionQue; //  Storage MySQL Connected queue 
	
	mutex _queueMutex;			//  Maintain thread safe mutexes for connection queues 
	atomic_int _connectionCnt;	//  Record the... Created by the connection connection Total connections for , No more than _maxSize
	condition_variable cv;		//  Connect the communication between the production thread and the consumption thread 
};

Source file

Connection.cpp

#include <mysql.h>
#include <string>
#include "Connection.h"
#include "public.h"
using namespace std;

//  Initialize database connection 
Connection::Connection()
{
    
	_conn = mysql_init(nullptr);
}

//  Release database connection resources 
Connection::~Connection()
{
    
	if (_conn != nullptr)
		mysql_close(_conn);
}

//  Connect to database 
bool Connection::connect(string ip, unsigned short port, string user, 
	string password, string dbname)
{
    
	MYSQL* p = mysql_real_connect(_conn, ip.c_str(), user.c_str(),
		password.c_str(), dbname.c_str(), port, nullptr, 0);
	return p != nullptr;
}

//  update operation  insert、delete、update
bool Connection::update(string sql)
{
    
	if (mysql_query(_conn, sql.c_str()))
	{
    
		LOG(" Update failed :" + sql);
		return false;
	}
	return true;
}

//  Query operation  select
MYSQL_RES* Connection::query(string sql)
{
    
	if (mysql_query(_conn, sql.c_str()))
	{
    
		LOG(" The query fails :" + sql);
		return nullptr;
	}
	return mysql_use_result(_conn);
}

//  Refresh the starting idle time of the connection 
void Connection::refreshAliveTime()
{
    
	_aliveTime = clock();
}

//  Return to the time of survival 
clock_t Connection::getAliveTime() const
{
    
	return clock() - _aliveTime;
}

mysql.ini

#  Configuration file of database connection pool 
ip=127.0.0.1
port=3306
username=root
password=123456
dbname=chat
initSize=10
maxSize=1024
#  The maximum idle time is seconds by default 
maxIdleTime=60
#  Connection timeout , In milliseconds 
connectionTimeOut=100

CommonConnectionPool.cpp

#include "CommonConnectionPool.h"
#include "public.h"

//  Thread safe lazy singleton mode function interface 
ConnectionPool* ConnectionPool::getConnectionPool()
{
    
	//  Static local variables , Compiler automatic lock and unlock
	static ConnectionPool pool; 
	return& pool;
}

//  Load configuration items from the configuration file 
bool ConnectionPool::loadConfigFile()
{
    
	FILE* pf = fopen("mysql.ini", "r");
	if (pf == nullptr)
	{
    
		LOG("mysql.ini file is not exist!");
		return false;
	}

	while (!feof(pf))
	{
    
		char line[1024] = {
     0 };
		fgets(line, 1024, pf);
		string str = line;
		int idx = str.find('=', 0);
		if (-1 == idx) //  Invalid configuration 
		{
    
			continue;
		}

		int endidx = str.find('\n', idx);
		string key = str.substr(0, idx);
		string value = str.substr(idx + 1, endidx - idx - 1);

		if (key == "ip")
		{
    
			_ip = value;
		}
		else if (key == "port")
		{
    
			_port = atoi(value.c_str());
		}
		else if (key == "username")
		{
    
			_username = value;
		}
		else if (key == "password")
		{
    
			_password = value;
		}
		else if (key == "dbname")
		{
    
			_dbname = value;
		}
		else if (key == "initSize")
		{
    
			_initSize = atoi(value.c_str());
		}
		else if (key == "maxSize")
		{
    
			_maxSize = atoi(value.c_str());
		}
		else if (key == "maxIdleTime")
		{
    
			_maxIdleTime = atoi(value.c_str());
		}
		else if (key == "connectionTimeOut")
		{
    
			_connectionTimeOut = atoi(value.c_str());
		}
	}
	return true;
}

//  Constructor for connection pool 
ConnectionPool::ConnectionPool()
{
    
	// 1. Load configuration items 
	if (!loadConfigFile())
	{
    
		return;
	}

	// 2. Create initial quantity connection 
	for (int i = 0; i < _initSize; ++i)
	{
    
		Connection* p = new Connection();
		p->connect(_ip, _port, _username, _password, _dbname);
		
		p->refreshAliveTime(); //  Refresh the start time of idle 
		_connectionQue.push(p);
		_connectionCnt++;
	}

	// 3. Start a new thread as the producer thread 
	thread produce(std::bind( & ConnectionPool::produceConnectionTask, this));
	produce.detach(); //  The guardian thread ( Detaching threads )

	// 4.  Start a new thread , Scan over maxIdleTime Of free connections , Recycle excess connections 
	thread scanner(std::bind(&ConnectionPool::scannerConnectionTask, this));
	scanner.detach();
}

//  producer : Running on a separate thread , Responsible for production connection 
void ConnectionPool::produceConnectionTask()
{
    
	//  loop ( Keep listening )
	for (; ;)
	{
    
		unique_lock<mutex> lock(_queueMutex);
		while (!_connectionQue.empty())
		{
    	
			cv.wait(lock); //  The queue is not empty , The production thread enters the waiting queue for the condition variable 
		}
		
		//  The number of connections has not reached the maximum , Continue creating new connections 
		if (_connectionCnt < _maxSize)
		{
    
			Connection* p = new Connection();
			p->connect(_ip, _port, _username, _password, _dbname);
			
			p->refreshAliveTime();	//  Refresh the start time of idle 
			_connectionQue.push(p);
			_connectionCnt++;
		}

		//  Wake up all threads in the waiting queue 
		cv.notify_all();	//  Notify consumer thread ,  You can consume and connect 
	}
}

//  Provide an interface to the outside , Provide an idle connection 
shared_ptr<Connection> ConnectionPool::getConnection()
{
    
	unique_lock<mutex> lock(_queueMutex);
	while (_connectionQue.empty())
	{
    
		//  Not directly sleep
		//  When I wake up after a timeout, I find that it is still empty , Just go back to nullptr
		if (cv_status::timeout == cv.wait_for(lock, std::chrono::milliseconds(_connectionTimeOut)))
		{
    
			if (_connectionQue.empty())
			{
    
				LOG(" Getting idle connection timed out ... Failed to get connection !");
				return nullptr;
			}
		}
	}

	/*  because shared_ptr At the time of deconstruction , Will be able to Connection Resource Direct delete fall ,  Equivalent to calling Connection Destructor of ,Connection I was close It fell off ,  So you need to customize how smart pointers release resources , Instead, return the resource to the queue  */
	shared_ptr<Connection> sp(_connectionQue.front(),
		[&](Connection* pcon) {
    
			//  This is called in the server application thread. , Thread safety needs to be considered 
			unique_lock<mutex> lock(_queueMutex);

			pcon->refreshAliveTime();	//  Refresh the start time of idle 
			_connectionQue.push(pcon);
		});
	_connectionQue.pop();

	//  Consume the last one in the queue Connection, The producer thread is notified of the production connection 
	cv.notify_all(); 
	return sp;
}

//  Scan over maxIdleTime Of free connections , Recycle excess connections 
void ConnectionPool::scannerConnectionTask()
{
    
	for (; ;)
	{
    
		//  adopt sleep Simulate the timing effect 
		this_thread::sleep_for(std::chrono::seconds(_maxIdleTime));

		//  Scan the entire queue , Release more than connections 
		unique_lock<mutex> lock(_queueMutex);
		while (_connectionCnt > _initSize)
		{
    
			Connection* p = _connectionQue.front();
			if (p->getAliveTime() >= (_maxIdleTime * 1000))
			{
    
				_connectionQue.pop();
				_connectionCnt--;
				delete p;	//  call  ~Connection();
			}
			else 
			{
    
				break; //  The connection of the team head does not exceed _maxIdleTime, There must be none in the back 
			}
		}
	}
}
原网站

版权声明
本文为[_ Soren]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/173/202206221339138380.html