一、數據庫連接池簡介
對於一個簡單的數據庫應用,如果對數據庫的訪問不是很頻繁,通常的做法是創建一個連接,用完就關閉,這樣做不會有明顯的性能上的開銷,但是對於一個副複雜的數據應用,建立一個數據庫連接需要消耗大量系統資源,頻繁的創建數據庫連接會大大的削弱應用性能,因此考慮到性能的問題,並不是每個用戶都創建並獨佔一個數據庫連接,數據庫連接池負責分配、管理和釋放數據庫連接,它允許應用程序重複使用一個現有的數據庫連接,而不是重新建立一個,使用完不會銷燬而是放回連接池。這項技術能明顯提高對數據庫操作的性能。
二、linux下的mysql函數
1.初始化一個連接句柄
-
MYSQL *mysql_init(MYSQL *mysql);//mysql是NULL指針,該函數將分配、初始化、並返回新對象。否則,將初始化對象,並返回對象的地址。
2.建立物理連接
-
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.斷開連接
- void mysql_close(MYSQL *connection);//斷開指定的鏈接。
4.選項設置
- 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. 錯誤處理
-
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命令
- int mysql_query(MYSQL *connection, const char *query);//該函數用來執行SQL命令,如果執行成功則返回0。
7.數據控制
-
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. 數據處理
-
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);//該函數可獲得與列字段相關信息的結構指針。
以下實現了一個簡單的數據庫連接池
- #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;
-
}
運行結果:
![linux基礎——linux下數據庫連接池的原理及編程實現]()
![linux基礎——linux下數據庫連接池的原理及編程實現]()