- 1 前言
- 2 连接池设计
- 2.1 连接池原理
- 2.2 数据结构设计
- 3 mysql连接过程
- 4 连接池的实现
- 4.1 连接池创建
- 4.2 连接池销毁
- 4.3 连接获取
- 4.4 连接归还
- 5 测试
连接池主要解决的问题就是,服务器对数据库的后半段的连接问题,这个过程连接对象是固定的,常规的连接完直接断开在连接建立时间浪费过长,同时连接需要多个连接同时工作来保证数据库的高效 *** 作,提高服务器的响应时间。
2 连接池设计 2.1 连接池原理连接池的主要是是完成服务器后半段的 *** 作,对数据库进行 *** 作的过程。一般场景下为了提高响应的速度,利用线程池处理多个连接同时进行连接 *** 作。下面是连接池的整体示意图:
连接池的工作原理就是初始化的时候创建好连接,并加入到空闲队列;当有任务来的时候从空闲队列取出任务;利用连接池进行数据 *** 作;最后使用完成后将连接归还队列,从而达到重复利用的功能。
这里涉及线程池和连接池 *** 作,为了更好的理解,这里进行对比:
连接池:
(1)连接池本身并没有执行能力,需要配合线程池一起使用;
(2)连接池的数量与执行线程数量相关,一般1比1;
(3)连接池被动 *** 作,池对象被任务获取,执行任务后归还。
线程池:
(1)线程池有自己的工作线程,可以自行消化任务;
(2)线程池数量与任务内容相关;
(3)线程池主动执行任务,执行完任务就销毁。
连接池包含:一个空闲连接队列、锁和信号量;连接对象节点包括:数据库连接初始化函数和释放函数;连接对象本身。
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语句;
- 关闭四次挥手;
连接池创建过程,主要是创建信号量和锁,同时创建连接。需要在连接前传入连接函数和数据库释放函数,包括完成连接的创建和连接好数据库。
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条)