使用c++编写一个通用的mysql连接池需要支持主备切换
由于MySQL连接池的实现涉及到很多细节,这里只提供一个简单的连接池实现供参考。如果需要更加完整和高效的实现,请参考第三方库或者自行实现。
该连接池实现主要包括以下几个部分:
1.连接池的初始化
2.连接池的连接和断开连接
3.连接池的主备切换
4.连接池中连接的使用
以下是一个简单的实现:
#include <mysql/mysql.h>
#include <queue>
#include <pthread.h>
#include <string>
#include <iostream>
#include <unistd.h>
using namespace std;
class MysqlConnPool {
public:
MysqlConnPool(string host, string user, string passwd, string db, int port, int max_conn);
~MysqlConnPool();
MYSQL* get_conn();
void free_conn(MYSQL* conn);
void switch_master_slave(string new_host);
private:
string host_;
string user_;
string passwd_;
string db_;
int port_;
int max_conn_;
queue<MYSQL*> conn_queue_;
pthread_mutex_t lock_;
pthread_cond_t cond_;
MYSQL* create_conn();
void destroy_conn(MYSQL* conn);
bool is_master_;
};
MysqlConnPool::MysqlConnPool(string host, string user, string passwd, string db, int port, int max_conn) {
host_ = host;
user_ = user;
passwd_ = passwd;
db_ = db;
port_ = port;
max_conn_ = max_conn;
is_master_ = true;
pthread_mutex_init(&lock_, NULL);
pthread_cond_init(&cond_, NULL);
for (int i = 0; i < max_conn_; i++) {
MYSQL* conn = create_conn();
if (conn) {
conn_queue_.push(conn);
} else {
cout << "create mysql connection error!" << endl;
}
}
}
MysqlConnPool::~MysqlConnPool() {
pthread_mutex_lock(&lock_);
while (!conn_queue_.empty()) {
MYSQL* conn = conn_queue_.front();
conn_queue_.pop();
destroy_conn(conn);
}
pthread_mutex_unlock(&lock_);
pthread_mutex_destroy(&lock_);
pthread_cond_destroy(&cond_);
}
MYSQL* MysqlConnPool::create_conn() {
MYSQL* conn = mysql_init(NULL);
if (conn) {
conn = mysql_real_connect(conn, host_.c_str(), user_.c_str(), passwd_.c_str(), db_.c_str(), port_, NULL, 0);
if (conn) {
mysql_query(conn, "set names utf8");//设置编码格式
} else {
cout << "connect to mysql error: " << mysql_error(conn) << endl;
}
} else {
cout << "init mysql error: " << mysql_error(conn) << endl;
}
return conn;
}
void MysqlConnPool::destroy_conn(MYSQL* conn) {
if (conn) {
mysql_close(conn);
}
}
MYSQL* MysqlConnPool::get_conn() {
MYSQL* conn = NULL;
pthread_mutex_lock(&lock_);
while (conn_queue_.empty()) {
pthread_cond_wait(&cond_, &lock_);
}
if (!conn_queue_.empty()) {
conn = conn_queue_.front();
conn_queue_.pop();
}
pthread_mutex_unlock(&lock_);
return conn;
}
void MysqlConnPool::free_conn(MYSQL* conn) {
pthread_mutex_lock(&lock_);
conn_queue_.push(conn);
pthread_cond_signal(&cond_);
pthread_mutex_unlock(&lock_);
}
void MysqlConnPool::switch_master_slave(string new_host) {
pthread_mutex_lock(&lock_);
while (!conn_queue_.empty()) {
MYSQL* conn = conn_queue_.front();
conn_queue_.pop();
destroy_conn(conn);
}
host_ = new_host;
is_master_ = !is_master_;
for (int i = 0; i < max_conn_; i++) {
MYSQL* conn = create_conn();
if (conn) {
conn_queue_.push(conn);
} else {
cout << "create mysql connection error!" << endl;
}
}
pthread_mutex_unlock(&lock_);
}
int main() {
MysqlConnPool pool("localhost", "root", "123456", "test", 3306, 5);
MYSQL* conn = pool.get_conn();
if (conn) {
mysql_query(conn, "select * from user");
MYSQL_RES* res = mysql_store_result(conn);
if (res) {
MYSQL_ROW row;
while ((row = mysql_fetch_row(res))) {
cout << row[0] << " " << row[1] << endl;
}
mysql_free_result(res);
}
pool.free_conn(conn);
}
sleep(5);//等待5秒
pool.switch_master_slave("192.168.0.1");//切换到备库
conn = pool.get_conn();
if (conn) {
mysql_query(conn, "select * from user");
MYSQL_RES* res = mysql_store_result(conn);
if (res) {
MYSQL_ROW row;
while ((row = mysql_fetch_row(res))) {
cout << row[0] << " " << row[1] << endl;
}
mysql_free_result(res);
}
pool.free_conn(conn);
}
return 0;
}
该连接池使用一个队列来保存连接,当需要获取连接时,从队列中取出一个连接,如果队列为空,则等待条件变量的通知。当需要释放连接时,将连接放回队列中,并发送条件变量的通知。当需要切换主备库时,先销毁所有连接,然后重新创建连接。需要注意的是,需要在切换主备库时,先加锁,以避免并发问题。
该连接池的主要缺点是,每次获取和释放连接时都需要加锁和解锁,会影响性能。如果用户数量较少,可以考虑使用一个线程来维护连接池,定期检查连接的可用性,并进行主备切换。如果用户数量较多,可以考虑使用多个连接池,并使用负载均衡算法来分配连接。
原文地址: https://www.cveoy.top/t/topic/rgS 著作权归作者所有。请勿转载和采集!