一、数据库连接池简介
对于一个简单的数据库应用,如果对数据库的访问不是很频繁,通常的做法是创建一个连接,用完就关闭,这样做不会有明显的性能上的开销,但是对于一个副复杂的数据应用,建立一个数据库连接需要消耗大量系统资源,频繁的创建数据库连接会大大的削弱应用性能,因此考虑到性能的问题,并不是每个用户都创建并独占一个数据库连接,数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个,使用完不会销毁而是放回连接池。这项技术能明显提高对数据库操作的性能。
二、linux下的mysql函数
1.初始化一个连接句柄
[cpp]
view plain
copy
- MYSQL *mysql_init(MYSQL *mysql);//mysql是NULL指针,该函数将分配、初始化、并返回新对象。否则,将初始化对象,并返回对象的地址。
2.建立物理连接
[cpp]
view plain
copy
- MYSQL *mysql_real_connect(MYSQL *connection,const char *server_host,const char *sql_user_name,const char *sql_password,const char *db_name,unsigned int port_number,const char *unix_socket_name,unsigned int flags);//connection参数为通过mysql_init函数创建的句柄,port_number和*unix_socket_name的值分别为0和NULL即可。如果连接成功,返回MYSQL*连接句柄(和第一个参数相同)。如果连接失败,返回NULL。
3.断开连接
[cpp]
view plain
copy
- void mysql_close(MYSQL *connection);//断开指定的链接。
4.选项设置
[cpp]
view plain
copy
- int mysql_options(MYSQL *mysql, enum mysql_option option, const void *arg);//可用于设置额外的连接选项,并影响连接的行为。可多次调用该函数来设置数个选项。应在mysql_init()之后、以及mysql_connect()或mysql_real_connect()之前调用mysql_options()。
- 主要选项:
- MYSQL_OPT_RECONNECT //显式方式设置再连接行为的方法。
- MYSQL_OPT_CONNECT_TIMEOUT //以秒为单位的连接超时。
5. 错误处理
[cpp]
view plain
copy
- unsigned int mysql_errno(MYSQL *connection);
- eg.if (mysql_errno(&my_connection))
- {
- fprintf(stderr, “Connection error %d: %s/n”, mysql_errno(&my_connection),mysql_error(&my_connection));
- }
6.执行SQL命令
[cpp]
view plain
copy
- int mysql_query(MYSQL *connection, const char *query);//该函数用来执行SQL命令,如果执行成功则返回0。
7.数据控制
[cpp]
view plain
copy
- MYSQL_RES *mysql_store_result(MYSQL *connection);//该函数成功时返回一个指向返回集的指针,否则返回NULL。
- my_ulonglong mysql_num_rows(MYSQL_RES *result);//该函数获取返回集中的行数,若为0表示没有返回行。
- MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);//该函数从mysql_store_result返回集中取出一行,当没有数据或者出差时返回NULL
- my_ulonglong mysql_num_rows(MYSQL_RES *result);//该函数获取返回集中的行数,若为0表示没有返回行。
8. 数据处理
[cpp]
view plain
copy
- unsigned int mysql_field_count(MYSQL *connection);//该函数获取返回集中数据的列数。此外,我们还可以将该函数用于其它情况,比如说确定mysql_store_result函数失败的原因;如果mysql_store_result返回NULL,而mysql_filed_count返回了一个大于0的数,说明是检索错误,但如果mysql_field_count返回0,则表明为存储错误。
- MYSQL_FIELD *mysql_fetch_field(MYSQL_RES *result);//该函数可获得与列字段相关信息的结构指针。
三、实现
以下实现了一个简单的数据库连接池
[cpp]
view plain
copy
- #include
- #include
- #include
- #include
- #include
- #define IP_LEN 15
- #define PORT_LEN 8
- #define DBNAME_LEN 64
- #define DBUSER_LEN 64
- #define PASSWD_LEN 64
- #define POOL_NUMBER 5
- #define LOG_STR_BUF_LEN 64
- //连接节点
- typedef struct _sql_node
- {
- MYSQL fd;//mysql对象文件描述符
- MYSQL *mysql_sock;//连接句柄
- pthread_mutex_t mutex;//互斥锁
- char used;//连接使用标志
- int index;//下标
- enum{DB_DISCONN, DB_CONN} sql_state;//当前节点与数据库的连接状态
- }sql_node;
- //数据库连接池
- typedef struct _sql_conn_pool
- {
- sql_node sql_pool[POOL_NUMBER];//连接池中的连接
- char ip[IP_LEN + 1];//ip
- int port;//端口 mysql端口默认3306
- char db_name[DBNAME_LEN + 1];//数据库名称
- char user[DBUSER_LEN + 1];//用户名
- char passwd[PASSWD_LEN + 1];//密码
- int pool_number;//池中连接数量
- }sql_conn_pool;
- //创建数据库连接池
- sql_conn_pool * sql_pool_create(int connect_pool_number, char ip[], int port, char name[], char user[], char passwd[])
- {
- sql_conn_pool *sp = NULL;
- if (!connect_pool_number || connect_pool_number < 1)
- {
- connect_pool_number = 1;
- }
- sp = (sql_conn_pool *)malloc(sizeof(sql_conn_pool));
- if (sp == NULL)
- {
- printf("malloc for sql connect pool error!\n");
- return NULL;
- }
- strcpy(sp->ip, ip);
- sp->port = port;
- strcpy(sp->db_name, name);
- strcpy(sp->user, user);
- strcpy(sp->passwd, passwd);
- //创建连接
- for (int index = 0; index < connect_pool_number; index++)
- {
- //创建失败
- if (-1 == create_connect(sp, &(sp->sql_pool[index])))
- {
- sql_pool_destroy(sp);
- return NULL;
- }
- printf("create database pool success\n");
- sp->sql_pool[index].index = index;
- sp->pool_number++;
- }
- return sp;
- }
- //创建连接
- static int create_connect(sql_conn_pool *sp, sql_node *node)
- {
- int ret = 0;
- int opt = 1;
- //初始化对象并返回对象地址
- if (NULL == mysql_init(&node->fd))
- {
- printf("mysql init error\n");
- ret = -1;
- }
- else
- {
- //mysql_real_connect非线程安全,用前需要加锁
- pthread_mutex_init(&node->mutex, NULL);
- if (!(node->mysql_sock = mysql_real_connect(&node->fd, sp->ip, sp->user, sp->passwd, sp->db_name, sp->port, NULL, 0)))
- {
- printf("couldn't connect to engine! %s \n", mysql_error(&node->fd));
- node->sql_state = DB_DISCONN;
- ret = 1;
- }
- else
- {
- node->used = 0;
- node->sql_state = DB_CONN;
- mysql_options(&node->fd, MYSQL_OPT_RECONNECT, &opt);
- opt = 3;//3s
- mysql_options(&node->fd, MYSQL_OPT_CONNECT_TIMEOUT, &opt);
- ret = 0;
- }
- }
- return ret;
- }
- //销毁数据库连接池
- void sql_pool_destroy(sql_conn_pool *sp)
- {
- for (int index = 0; index < sp->pool_number; index++)
- {
- if (NULL != sp->sql_pool[index].mysql_sock)
- {
- mysql_close(sp->sql_pool[index].mysql_sock);
- sp->sql_pool[index].mysql_sock = NULL;
- }
- sp->sql_pool[index].sql_state = DB_DISCONN;
- }
- }
- //从数据库连接池中获取一个未使用的连接
- sql_node *get_db_connect_from_pool(sql_conn_pool *sp)
- {
- int start_index = 0, index = 0, loop_index;
- int ping_ret;
- srand((int)time(0));
- start_index = rand() % sp->pool_number;
- for (loop_index = 0; loop_index < sp->pool_number; loop_index++)
- {
- index = (start_index + loop_index) % sp->pool_number;
- if (!pthread_mutex_trylock(&sp->sql_pool[index].mutex))
- {
- if (DB_DISCONN == sp->sql_pool[index].sql_state)
- {
- //重新连接
- if (0 != create_connect(sp, &(sp->sql_pool[index])))
- {
- //重新连接失败
- release_sock_to_sql_pool(&(sp->sql_pool[index]));
- continue;
- }
- }
- }
- ping_ret = mysql_ping(sp->sql_pool[index].mysql_sock);
- if (0 != ping_ret)
- {
- printf("mysql ping error!\n");
- sp->sql_pool[index].sql_state = DB_DISCONN;
- release_sock_to_sql_pool(&(sp->sql_pool[index]));
- }
- else
- {
- sp->sql_pool[index].used = 1;
- break;
- }
- }
- if (loop_index == sp->pool_number)
- {
- return NULL;
- }
- else
- {
- return &(sp->sql_pool[index]);
- }
- }
- //将使用完的连接还给连接池
- void release_sock_to_sql_pool(sql_node *node)
- {
- node->used = 0;
- pthread_mutex_unlock(&node->mutex);
- }
- int main()
- {
- MYSQL_FIELD *fd;
- sql_conn_pool *sp = sql_pool_create(POOL_NUMBER, "192.168.238.132", 3306, "yexin", "root", "1234567890");
- sql_node *node = get_db_connect_from_pool(sp);
- if (NULL == node)
- {
- printf("get sql pool node error.\n");
- return -1;
- }
- if (mysql_query(&(node->fd), "delete from student where sno = '0174'"))
- {
- printf("query error.\n");
- return -1;
- }
- else
- {
- printf("delete succeed!\n");
- }
- sql_pool_destroy(sp);
- return 0;
- }

