企业级连接池实现

1 前言

连接池主要解决的问题就是,服务器对数据库的后半段的连接问题,这个过程连接对象是固定的,常规的连接完直接断开在连接建立时间浪费过长,同时连接需要多个连接同时工作来保证数据库的高效操作,提高服务器的响应时间。

2 连接池设计

2.1 连接池原理

连接池的主要是是完成服务器后半段的操作,对数据库进行操作的过程。一般场景下为了提高响应的速度,利用线程池处理多个连接同时进行连接操作。下面是连接池的整体示意图:
在这里插入图片描述
连接池的工作原理就是初始化的时候创建好连接,并加入到空闲队列;当有任务来的时候从空闲队列取出任务;利用连接池进行数据操作;最后使用完成后将连接归还队列,从而达到重复利用的功能。
在这里插入图片描述
这里涉及线程池和连接池操作,为了更好的理解,这里进行对比:
连接池:
(1)连接池本身并没有执行能力,需要配合线程池一起使用;
(2)连接池的数量与执行线程数量相关,一般1比1;
(3)连接池被动操作,池对象被任务获取,执行任务后归还。
线程池:
(1)线程池有自己的工作线程,可以自行消化任务;
(2)线程池数量与任务内容相关;
(3)线程池主动执行任务,执行完任务就销毁。

2.2 数据结构设计

连接池包含:一个空闲连接队列、锁和信号量;连接对象节点包括:数据库连接初始化函数和释放函数;连接对象本身。

typedef struct connecter {

	db_init init;
	db_denit denit;
	void * conn;
	struct connecter *prev;
	struct connecter *next;
}connecter;

typedef struct con_pool {
	
	connecter *cons; 
	int terminate;

	pthread_cond_t cond;
	pthread_mutex_t mtx;
}con_pool;

3 mysql连接过程

mysql连接操作是一个耗时的操作,分为四个步骤:一个是三次握手建立TCP连接;第二个是账号密码的人数在过程;第三是执行mysql语句;最后是关闭连接。连接池的作用就是把连接、认证和断开操作屏蔽,只保留mysql操作是时间,大大的缩短交互时间。

  • 三次握手;
  • 账号密码认证;
  • 执行sql语句;
  • 关闭四次挥手;

4 连接池的实现

4.1 连接池创建

连接池创建过程,主要是创建信号量和锁,同时创建连接。需要在连接前传入连接函数和数据库释放函数,包括完成连接的创建和连接好数据库。

int con_pool_create(con_pool *pool, int num_cons, db_init init, void *init_data, db_denit denit) {

	// 
	if (pool == NULL) return -1;
	
	if (num_cons < 1) num_cons = 1;
	memset(pool, 0, sizeof(con_pool));

	// cond
	pthread_cond_t blank_cond = PTHREAD_COND_INITIALIZER;
	memcpy(&pool->cond, &blank_cond, sizeof(pthread_cond_t));

	// mutex
	pthread_mutex_t blank_mtx = PTHREAD_MUTEX_INITIALIZER;
	memcpy(&pool->mtx, &blank_mtx, sizeof(pthread_mutex_t));

	int idx = 0;
	for (idx = 0;idx < num_cons;idx ++) {

		connecter *con = (connecter *)malloc(sizeof(connecter));
		if (con == NULL) {
			perror("malloc");
			return idx;
		}
		memset(con, 0, sizeof(connecter));
		con->init = init;
		con->denit = denit;
		if(init(&con->conn, init_data))
		{
			free(con);
			return -1;
		}

		LL_ADD(con, pool->cons);
	}

	return idx;
}

4.2 连接池销毁

连接池销毁过程,先要通知连接池暂停服务,关闭连接获取,同时释放连接,利用回调释放对应的数据库连接。

int con_pool_destroy(con_pool *pool) {

	pool->terminate = 1;

	pthread_mutex_lock(&pool->mtx);
	pthread_cond_broadcast(&pool->cond);
	pthread_mutex_unlock(&pool->mtx);

	connecter *con = pool->cons;
	connecter *tmp = NULL;
	while(con)
	{
		tmp = con;
		con = con->next;
		tmp->denit(tmp);
		free(tmp);
	}

}

4.3 连接获取

连接的获取是一个多线程操作,需要上锁,对连接队列没有可用连接时,目前采用的是等待到有连接再操作。后续也可以根据需要增加超时操作等等。连接获取完成后需要移除空闲队列,防止其他任务使用。

connecter *con_pool_get_con(con_pool *pool) {

	pthread_mutex_lock(&pool->mtx);
	while (pool->cons == NULL) {
		if (pool->terminate) break;
		pthread_cond_wait(&pool->cond, &pool->mtx);
	}

	if (pool->terminate) {
		pthread_mutex_unlock(&pool->mtx);
		return NULL;
	}

	connecter *con = pool->cons;
	if (con) {
		LL_REMOVE(con, pool->cons);
	}

	pthread_mutex_unlock(&pool->mtx);

	if (con == NULL) return NULL;
	
	return con;
}

4.4 连接归还

连接归还操作是在任务处理完成后归还连接,这里需要重新加入空闲队列,并且通知连接队列有数据加入,方便取出连接操作。

int con_pool_back_con(con_pool *pool, connecter *con) {

	if(!pool || !con) return -1;
	
	pthread_mutex_lock(&pool->mtx);
	LL_ADD(con, pool->cons);
	pthread_cond_signal(&pool->cond);
	pthread_mutex_unlock(&pool->mtx);

	return 0;
}

5 测试

连接测试,采用10个线程和10个连接同时操作mysql插入1000条数据,具体用时1416ms
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值