最近都在查看MYsql C API文檔,也遇到了很多問題,下面來簡單的做一個總結。
mysql多線程問題
- mysql多線程處理不好,經常會發生coredump,見使用Mysql出core一文。
單線程
- 一般情況下,單線程連接mysql代碼如下:
1 /* 2 single_thread_mysql_client.cpp 3 */ 4 #include <stdio.h> 5 #include <string.h> 6 #include <stdlib.h> 7 #include <mysql/mysql.h> 8 #include <pthread.h> 9 #include <unistd.h> 10 11 #define DBHOST "localhost" 12 #define DBUSER "pca" 13 #define DBPASS "pca" 14 #define DBPORT 3306 15 #define DBNAME "dxponline" 16 #define DBSOCK NULL //"/var/lib/mysql/mysql.sock" 17 #define DBPCNT 0 18 19 int main() 20 { 21 MYSQL_RES *result; 22 MYSQL_ROW row; 23 MYSQL_FIELD *field; 24 unsigned int num_fields; 25 unsigned int i; 26 const char *pStatement = "SHOW TABLES"; 27 mysql_library_init(0, NULL, NULL); 28 MYSQL *mysql = mysql_init(NULL); 29 unsigned int timeout = 3000; 30 mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, &timeout); 31 32 if (mysql_real_connect(mysql, DBHOST, DBUSER, DBPASS, DBNAME, DBPORT, DBSOCK, DBPCNT) == NULL) 33 { 34 printf("connect failed: %s\n", mysql_error(mysql)); 35 mysql_close(mysql); 36 mysql_library_end(); 37 return 0; 38 } 39 40 printf("connect succssfully\n"); 41 42 if (0 != mysql_real_query(mysql, pStatement, strlen(pStatement))) 43 { 44 printf("query failed: %s\n", mysql_error(mysql)); 45 mysql_close(mysql); 46 mysql_library_end(); 47 return 0; 48 } 49 50 result = mysql_store_result(mysql); 51 52 if (result == NULL) 53 { 54 printf("fetch result failed: %s\n", mysql_error(mysql)); 55 mysql_close(mysql); 56 mysql_library_end(); 57 return 0; 58 } 59 60 num_fields = mysql_num_fields(result); 61 printf("numbers of result: %d\n", num_fields); 62 63 while (NULL != (field = mysql_fetch_field(result))) 64 { 65 printf("field name: %s\n", field->name); 66 } 67 68 while (NULL != (row = mysql_fetch_row(result))) 69 { 70 unsigned long *lengths; 71 lengths = mysql_fetch_lengths(result); 72 73 for (i = 0; i < num_fields; i++) 74 { 75 printf("{%.*s} ", (int) lengths[i], row[i] ? row[i] : "NULL"); 76 } 77 78 printf("\n"); 79 } 80 81 mysql_free_result(result); 82 mysql_close(mysql); 83 mysql_library_end(); 84 return 0; 85 }
-
執行
make single_thread_mysql_client LDFLAGS="-g -O2 -L/usr/lib64/mysql -lmysqlclient -lpthread -lz -lm -lssl -lcrypto -ldl"
即可獲得對應單線程二進制。
多線程
- 多線程主要需要注意以下幾點
mysql_library_init
和mysql_library_end
需要放入主線程;- 連接句柄需要多個才能加快並發,而連接句柄由
mysql_init
生成,而mysql_init
跟隨機函數rand
有點相似,第一次需要初始化后才能線程安全,所以需要使用mysql_thread_init
和mysql_thread_end
兩個函數來保證線程安全;
- 一般多線程連接mysql代碼如下
1 /* 2 muti_thread_mysql_client.cpp 3 */ 4 #include <stdio.h> 5 #include <string.h> 6 #include <stdlib.h> 7 #include <mysql/mysql.h> 8 #include <pthread.h> 9 #include <unistd.h> 10 11 #define THREAD_NUM 4 12 #define DBHOST "localhost" 13 #define DBUSER "pca" 14 #define DBPASS "pca" 15 #define DBPORT 3306 16 #define DBNAME "dxponline" 17 #define DBSOCK NULL //"/var/lib/mysql/mysql.sock" 18 #define DBPCNT 0 19 20 typedef struct ThreadArgsST 21 { 22 int id; 23 pthread_t *thread_id; 24 } ThreadArgs; 25 26 void *func(void *arg) 27 { 28 ThreadArgs *args = (ThreadArgs *)arg; 29 MYSQL_RES *result; 30 MYSQL_ROW row; 31 MYSQL_FIELD *field; 32 unsigned int num_fields; 33 unsigned int i; 34 unsigned int timeout = 3000; 35 const char *pStatement = "SHOW TABLES"; 36 mysql_thread_init(); 37 MYSQL *mysql = mysql_init(NULL); 38 39 if (mysql == NULL) 40 { 41 printf("[%ld][%d]mysql init failed: %s\n", *args->thread_id, args->id, mysql_error(mysql)); 42 return (void *)0; 43 } 44 45 mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, &timeout); 46 47 if (mysql_real_connect(mysql, DBHOST, DBUSER, DBPASS, DBNAME, DBPORT, DBSOCK, DBPCNT) == NULL) 48 { 49 printf("[%ld][%d]connect failed: %s\n", *args->thread_id, args->id, mysql_error(mysql)); 50 mysql_close(mysql); 51 mysql_thread_end(); 52 return (void *)0; 53 } 54 55 printf("[%ld][%d]connect succssfully\n", *args->thread_id, args->id); 56 57 if (0 != mysql_real_query(mysql, pStatement, strlen(pStatement))) 58 { 59 printf("[%ld][%d]query failed: %s\n", *args->thread_id, args->id, mysql_error(mysql)); 60 mysql_close(mysql); 61 mysql_thread_end(); 62 return (void *)0; 63 } 64 65 result = mysql_store_result(mysql); 66 67 if (result == NULL) 68 { 69 printf("[%ld][%d]fetch result failed: %s\n", *args->thread_id, args->id, mysql_error(mysql)); 70 mysql_close(mysql); 71 mysql_thread_end(); 72 return (void *)0; 73 } 74 75 num_fields = mysql_num_fields(result); 76 printf("[%ld][%d]numbers of result: %d\n", *args->thread_id, args->id, num_fields); 77 78 while (NULL != (field = mysql_fetch_field(result))) 79 { 80 printf("[%ld][%d]field name: %s\n", *args->thread_id, args->id, field->name); 81 } 82 83 while (NULL != (row = mysql_fetch_row(result))) 84 { 85 unsigned long *lengths; 86 lengths = mysql_fetch_lengths(result); 87 88 for (i = 0; i < num_fields; i++) 89 { 90 printf("[%ld][%d]{%.*s} ", *args->thread_id, args->id, (int) lengths[i], row[i] ? row[i] : "NULL"); 91 } 92 93 printf("\n"); 94 } 95 96 mysql_free_result(result); 97 mysql_close(mysql); 98 mysql_thread_end(); 99 return (void *)0; 100 } 101 102 int main(int argc, char *argv[]) 103 { 104 int thread_num; 105 106 if (argc == 2) 107 { 108 thread_num = atoi(argv[1]); 109 } 110 else 111 { 112 thread_num = THREAD_NUM; 113 } 114 115 mysql_library_init(0, NULL, NULL); 116 printf("argc: %d and thread_num: %d\n", argc, thread_num); 117 118 do 119 { 120 pthread_t *pTh = new pthread_t[thread_num]; 121 ThreadArgs *pArgs = new ThreadArgs[thread_num]; 122 int i; 123 124 for (i = 0; i < thread_num; i ++) 125 { 126 pArgs[i].id = i; 127 pArgs[i].thread_id = &pTh[i]; 128 129 if (0 != pthread_create(&pTh[i], NULL, func, &pArgs[i])) 130 { 131 printf("pthread_create failed\n"); 132 continue; 133 } 134 } 135 136 for (i = 0; i < thread_num; i ++) 137 { 138 pthread_join(pTh[i], NULL); 139 } 140 141 delete[] pTh; 142 delete[] pArgs; 143 } 144 while (0); 145 146 mysql_library_end(); 147 return 0; 148 }
-
執行
make muti_thread_mysql_client LDFLAGS="-g -O2 -L/usr/lib64/mysql -lmysqlclient -lpthread -lz -lm -lssl -lcrypto -ldl"
即可獲得對應單線程二進制。
-
連接數與連接句柄是一一對應關系,故一般使用長連接,所以需要連接池,所以上面的代碼可以有優化的空間,代碼見:
1 /* 2 muti_thread_mysql_client_pool.cpp 3 */ 4 #include <stdio.h> 5 #include <string.h> 6 #include <stdlib.h> 7 #include <mysql/mysql.h> 8 #include <pthread.h> 9 #include <unistd.h> 10 #include <queue> 11 #include <string> 12 13 #define THREAD_NUM 4 14 #define DBHOST "localhost" 15 #define DBUSER "pca" 16 #define DBPASS "pca" 17 #define DBPORT 3306 18 #define DBNAME "dxponline" 19 #define DBSOCK NULL //"/var/lib/mysql/mysql.sock" 20 #define DBPCNT 0 21 22 using namespace std; 23 24 class CBlockQueue; 25 typedef struct ThreadArgsST 26 { 27 int id; 28 pthread_t *thread_id; 29 CBlockQueue *pQueue; 30 } ThreadArgs; 31 32 class CMutex 33 { 34 public: 35 CMutex() 36 { 37 pthread_mutex_init(&_mutex, NULL); 38 } 39 ~CMutex() 40 { 41 pthread_mutex_destroy(&_mutex); 42 } 43 44 int32_t lock() 45 { 46 return pthread_mutex_lock(&_mutex); 47 } 48 49 int32_t unlock() 50 { 51 return pthread_mutex_unlock(&_mutex); 52 } 53 54 int32_t trylock() 55 { 56 return pthread_mutex_trylock(&_mutex); 57 } 58 59 private: 60 pthread_mutex_t _mutex; 61 }; 62 63 class CGlobalFunction 64 { 65 public: 66 static MYSQL *connect() 67 { 68 unsigned int timeout = 3000; 69 mysql_thread_init(); 70 MYSQL *mysql = mysql_init(NULL); 71 72 if (mysql == NULL) 73 { 74 printf("mysql init failed: %s\n", mysql_error(mysql)); 75 return NULL; 76 } 77 78 mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, &timeout); 79 80 if (mysql_real_connect(mysql, DBHOST, DBUSER, DBPASS, DBNAME, DBPORT, DBSOCK, DBPCNT) == NULL) 81 { 82 printf("connect failed: %s\n", mysql_error(mysql)); 83 mysql_close(mysql); 84 mysql_thread_end(); 85 return NULL; 86 } 87 88 printf("connect succssfully\n"); 89 return mysql; 90 } 91 }; 92 93 class CBlockQueue : public CMutex 94 { 95 public: 96 CBlockQueue() : _size(512) 97 { 98 } 99 ~CBlockQueue() 100 { 101 } 102 void set_size(int size) 103 { 104 _size = size; 105 } 106 int size() 107 { 108 this->lock(); 109 int size = q.size(); 110 this->unlock(); 111 return size; 112 } 113 bool push(void *m) 114 { 115 this->lock(); 116 // TODO 117 /* 118 if (q.size() > _size) 119 { 120 this->unlock(); 121 fprintf(stderr, "[QUEUE_IS_FULL]queue size over limit from push: %d\n", _size); 122 return false; 123 } 124 */ 125 q.push(m); 126 this->unlock(); 127 return true; 128 } 129 130 void *pop() 131 { 132 this->lock(); 133 134 if (q.empty()) 135 { 136 this->unlock(); 137 fprintf(stderr, "[QUEUE_IS_EMPTY]queue is no item from pop"); 138 return NULL; 139 } 140 141 void *m = q.front(); 142 q.pop(); 143 this->unlock(); 144 return m; 145 } 146 147 private: 148 queue q; 149 int _size; 150 }; 151 152 void *func(void *arg) 153 { 154 ThreadArgs *args = (ThreadArgs *)arg; 155 MYSQL_RES *result; 156 MYSQL_ROW row; 157 MYSQL_FIELD *field; 158 bool pushed = true; 159 unsigned int num_fields; 160 unsigned int i; 161 const char *pStatement = "SHOW TABLES"; 162 MYSQL *db = (MYSQL *)args->pQueue->pop(); 163 164 if (db == NULL) 165 { 166 db = CGlobalFunction::connect(); 167 168 if (db == NULL) 169 { 170 printf("[%ld][%d]mysql connect failed\n", *args->thread_id, args->id); 171 return (void *)0; 172 } 173 } 174 175 if (0 != mysql_real_query(db, pStatement, strlen(pStatement))) 176 { 177 printf("[%ld][%d]query failed: %s\n", *args->thread_id, args->id, mysql_error(db)); 178 args->pQueue->push(db); 179 return (void *)0; 180 } 181 182 result = mysql_store_result(db); 183 184 if (result == NULL) 185 { 186 printf("[%ld][%d]fetch result failed: %s\n", *args->thread_id, args->id, mysql_error(db)); 187 args->pQueue->push(db); 188 return (void *)0; 189 } 190 191 num_fields = mysql_num_fields(result); 192 printf("[%ld][%d]numbers of result: %d\n", *args->thread_id, args->id, num_fields); 193 194 while (NULL != (field = mysql_fetch_field(result))) 195 { 196 printf("[%ld][%d]field name: %s\n", *args->thread_id, args->id, field->name); 197 } 198 199 while (NULL != (row = mysql_fetch_row(result))) 200 { 201 unsigned long *lengths; 202 lengths = mysql_fetch_lengths(result); 203 204 for (i = 0; i < num_fields; i++) 205 { 206 printf("[%ld][%d]{%.*s} ", *args->thread_id, args->id, (int) lengths[i], row[i] ? row[i] : "NULL"); 207 } 208 209 printf("\n"); 210 } 211 212 mysql_free_result(result); 213 args->pQueue->push(db); 214 return (void *)0; 215 } 216 217 int main(int argc, char *argv[]) 218 { 219 CBlockQueue queue; 220 int thread_num; 221 222 if (argc == 2) 223 { 224 thread_num = atoi(argv[1]); 225 } 226 else 227 { 228 thread_num = THREAD_NUM; 229 } 230 231 mysql_library_init(0, NULL, NULL); 232 printf("argc: %d and thread_num: %d\n", argc, thread_num); 233 234 do 235 { 236 int i; 237 pthread_t *pTh = new pthread_t[thread_num]; 238 ThreadArgs *pArgs = new ThreadArgs[thread_num]; 239 240 for (i = 0; i < thread_num; i ++) 241 { 242 pArgs[i].id = i; 243 pArgs[i].thread_id = &pTh[i]; 244 pArgs[i].pQueue = &queue; 245 246 if (0 != pthread_create(&pTh[i], NULL, func, &pArgs[i])) 247 { 248 printf("pthread_create failed\n"); 249 continue; 250 } 251 } 252 253 for (i = 0; i < thread_num; i ++) 254 { 255 pthread_join(pTh[i], NULL); 256 } 257 258 delete[] pTh; 259 delete[] pArgs; 260 int qsize = queue.size(); 261 262 for (i = 0; i < qsize; i ++) 263 { 264 MYSQL *db = (MYSQL *)queue.pop(); 265 266 if (NULL != db) 267 { 268 mysql_close(db); 269 mysql_thread_end(); 270 } 271 } 272 } 273 while (0); 274 275 mysql_library_end(); 276 return 0; 277 }
-
執行
make muti_thread_mysql_client_pool LDFLAGS="-g -O2 -L/usr/lib64/mysql -lmysqlclient -lpthread -lz -lm -lssl -lcrypto -ldl"
即可獲得對應單線程二進制。
-
上述代碼就是利用隊列來保持mysql連接,達到優化連接數。
總結
-
mysql連接與多線程處理不好,可能會造成很多問題,如
*MySQL Connection failed (#2058): This handle is already connected. Use a separate handle for each connection.*
Error in my_thread_global_end(): 1 threads didn't exit
- 甚至出現coredump
-
關於多線程連接mysql優化的思想,其實可以擴展到其他連接,如HTTP、Socket等連接中;
測試多線程連接Mysql:
1 int main() 2 { 3 mysql_library_init(0,NULL,NULL); 4 pthread_t producer; 5 pthread_t consumer_1; 6 pthread_t consumer_2; 7 //produce_fun不涉及數據庫鏈接,不貼出來 8 pthread_create(&producer,NULL,produce_fun,NULL); 9 pthread_create(&consumer_1,NULL,consume_fun,NULL); 10 pthread_create(&consumer_2,NULL,consume_fun,NULL); 11 //下面的三句非常重要,main線程等待其他三個線程的結束,避免main線程執行到mysql_library_end時退出,而 12 //其他三個線程仍然在運行並報錯的情形 13 pthread_join(producer,NULL); 14 pthread_join(consumer_1,NULL); 15 pthread_join(consumer_2,NULL); 16 mysql_library_end(); 17 return 0; 18 } 19 20 void addRecord_d(MYSQL *ptr_db,const char *t_name,int item){ 21 char query_buffer[100]; 22 sprintf(query_buffer,"insert into %s values(0,%d)",t_name,item); 23 int ret=mysql_query(ptr_db,query_buffer); 24 if(ret){ 25 fprintf(stderr,"%s%s\n","cannot add record to ",t_name); 26 return; 27 } 28 29 unsigned long long update_id=mysql_insert_id(ptr_db); 30 printf("add record (%llu,%d) ok.",update_id,item); 31 } 32 33 void * consume_fun(void *arg){ 34 MYSQL db; 35 MYSQL *ptr_db=mysql_init(&db); 36 mysql_real_connect(); 37 //藍色部分可以改為其他任何帶操作數據庫語句的代碼 38 //procedure 39 while(1){ 40 printf("consumer..."); 41 int item=consume(&p); 42 addRecord_d(ptr_db,"test",item); 43 } 44 mysql_thread_end(); 45 pthread_exit(NULL); 46 }
C/C++中調用api設置mysql連接的編碼方式
mysql在C/C++中調用api設置連接mysql的編碼方式有以下幾種方法:
1. mysqli_set_charset
調用示例:
- ret = mysql_set_character_set(mysql, "utf8");
說明:
推薦使用的設置方法,與mysql的連接斷開自動重連后仍能保持設置的編碼格式,並且影響mysql_real_escape_string函數功能,使mysql_real_escape_string函數使用設置的編碼格式轉義字符串。
但該函數在mysql5.0.5版本以后才支持,故版本太低者...。
2. 執行sql語句:SET NAMES
調用示例:
- ret = mysql_real_query(mysql, "SET NAMES UTF8;",
- (unsigned long) strlen ("SET NAMES UTF8;"));
說明:
使用sql語句執行,只能影響當前與數據庫的連接,斷開自動重連后編碼格式會重置為默認的配置。
3. 設置MYSQL_SET_CHARSET_NAME屬性
調用示例:
- ret = mysql_options(mysql, MYSQL_SET_CHARSET_NAME, "utf8");
說明:
跟mysql_set_character_set類似,斷開自動重連后仍能保持設置的編碼格式,只是不會影響到mysql_real_escape_string函數。
並且在mysql5.0.5版本都可以使用,低版本可以使用該方法代替。
需要特別說明的是只有在調用mysql_real_connect連接數據庫之前修改該屬性才會生效。
mysql控制自動重連行為
當向mysql server發送statement時,mysql客戶端發現連接失效后會自動嘗試重新連接server。如果"自動重連"狀態是enabled,客戶端嘗試連接server,並在連接成功后重新發送statement.
"自動重連“默認是disabled的。
如果應用程序需要知道連接是否可用(可以退出程序或顯示相應的提示信息),確認“自動重連”是disabled。可以通過調用包含MYSQL_OPT_RECONNECT參數的mysql_options()函數以確認"自動重連"是否disabled:
my_bool reconnect = 0; mysql_options(&mysql, MYSQL_OPT_RECONNECT, &reconnect);
如果連接已經斷開,mysql_ping()依賴“自動重連”的狀態。如果“自動重連”是enabled,
mysql_ping()會重新獲取連接。否則,會返回錯誤。
有些客戶端程序可能提供了控制自動重連的功能。比如,mysql默認是允許重連的,但是使用 --skip-reconnect 選項將關閉這個行為。
如果發生了自動重連(比如,調用了mysql_ping()
),自動重連是透明的。為了檢查是否發生了重連,在調用mysql_ping()函數前,先調用
mysql_thread_id()函數獲取原始的連接id,然后調用
mysql_ping(),在調用
mysql_thread_id()函數,對比兩次
mysql_thread_id()的結果是否變化了。
“自動重連”很方便,因為你不需要再實現自己重連代碼,但是一旦發生了自動重連,connection的一些狀態在server端就會被重置,而你的應用程序得不到這些變化的通知。
下面列出連接相關的狀態變化:
-
任何未提交的事務將會回滾並且連接autocommit屬性將會重置
-
事務中的鎖將會被釋放。
-
所有的臨時表將會關閉(並釋放)。
-
Session中的變量會重新初始化為系統默認值,包括在statements中顯式聲明的變量,比如
SET NAMES。
-
用戶自定義的變量將會丟失。
-
Prepared statements將釋放。
-
HANDLER
變量將會關閉。 -
LAST_INSERT_ID()的值將會重置為0.
-
通過
GET_LOCK()獲取的鎖將會釋放。
如果連接失效,可能connection的session在server端依然在運行,當server沒有檢測到客戶端失去連接。在這種情況下,原來connection的鎖依然屬於那個session,你可以調用mysql_kill()函數kill掉它。
Linux下C語言連接MySQL找不到mysql.h解決辦法
昨天是把MySQL裝上去了,今天嘗試用C語言訪問連接MySQL,發現使用編譯指令:gcc -I/usr/include/mysql connect.c -lmysqlclient -o connect之后,提示找不到“mysql.h”文件,T_T|||。
原因其實很簡單了,昨天我只裝了server和client兩個包,對於平常的使用,這已經足夠了,但對於要在Linux下進行數據庫的開發,則還需要安裝devel開發包,並且該開發包的版本應該和我之前所安裝的server和client包版本一致,否則會發生沖突而導致無法安裝。
server和client包的安裝見上一篇日志:Linux(Fedora 9)卸載自帶的MySQL並安裝MySQL的詳細步驟。
好了,我們來安裝devel包,注意版本要保持一致:
- [root@localhost install]# rpm -ivh MySQL-devel-community-5.1.46-1.rhel5.i386.rpm
- Preparing... ########################################### [100%]
- 1:MySQL-devel-community ########################################### [100%]
這次為了避免再出現問題,我把共享組件包shared也裝上去了,哈哈:
- [root@localhost install]# rpm -ivh MySQL-shared-community-5.1.46-1.rhel5.i386.rpm
- Preparing... ########################################### [100%]
- 1:MySQL-shared-community ########################################### [100%]
裝完之后,再編譯就通過了,此時的“mysql.h”已經出現在了/usr/include/mysql目錄下面。Happy~
undefined reference to `mysql_init'解決辦法
寫了一個很簡單的測試數據庫連接的程序conn.c如下:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include "/usr/local/mysql/include/mysql/mysql.h" 4 #include <string.h> 5 int main(int argc, char *argv[]) 6 { 7 MYSQL my_connection; 8 mysql_init(&my_connection); 9 if (mysql_real_connect(&my_connection, "localhost", "root", "","mysql",0,NULL,CLIENT_FOUND_ROWS)) 10 { 11 printf("Connection success\n"); 12 mysql_close(&my_connection); 13 } 14 else 15 { 16 fprintf(stderr, "Connection failed\n"); 17 if (mysql_errno(&my_connection)) 18 { 19 fprintf(stderr, "Connection error %d: %s\n",mysql_errno(&my_connection),mysql_error(&my_connection)); 20 } 21 } 22 return EXIT_SUCCESS; 23 }
gcc編譯:gcc -o conn conn.c出現如下錯誤:
/tmp/ccY0JTdh.o(.text+0x1e): In function `main':
: undefined reference to `mysql_init'
/tmp/ccY0JTdh.o(.text+0x47): In function `main':
: undefined reference to `mysql_real_connect'
/tmp/ccY0JTdh.o(.text+0x6d): In function `main':
: undefined reference to `mysql_close'
/tmp/ccY0JTdh.o(.text+0x97): In function `main':
: undefined reference to `mysql_errno'
/tmp/ccY0JTdh.o(.text+0xad): In function `main':
: undefined reference to `mysql_error'
/tmp/ccY0JTdh.o(.text+0xc0): In function `main':
: undefined reference to `mysql_errno'
collect2: ld returned 1 exit status
出現該錯誤的原因是因為編譯器找不到mysql_init,mysql_close等的具體實現.雖然我們包括了正確的頭文件,但是 我們在編譯的時候還是要連接確定的庫.對於一些常用的函數的實現,gcc編譯器會自動去連接一些常用庫,這樣我們就沒有必要自己去指定了,如:printf函數.在本程序中要通過-L選項包含庫文件的路徑:
gcc -o conn conn.c -L /usr/local/mysql/lib/*.a -lz
通過,用*.a將庫全部包含進來拉,其實只要包含mysqlclient.a就可以. -lz什么意思我也不清楚了
undefined reference to 'dlopen';undefined reference to 'dlclose';undefined reference to 'dlerror'等問題
在linux下,編譯鏈接的時候,經常會遇到這樣一個問題,undefined reference to.....,引起這個問題的原因在於在鏈接的時候缺少選項。下面舉幾個例子,並給出解決辦法。
1、undefined reference to `dlerror'
undefined reference to `dlopen'
undefined reference to `dlerror';;解決方法:在makefile的 ldflags 后面把選項 -ldl添加上即可
2、undefined reference to `main';;解決方法:在makefile的 ldflags 后面添加 -nostartfiles 選項
3、undefined reference to `pthread_setspecific'
undefined reference to `pthread_key_delete'
undefined reference to `pthread_key_create'::解決辦法:在makefile的LDFLAGS后面添加 -lpthread 選項。
最后::如果undefined reference to后面的內容是在自己的文件中聲明或定義的東西,就不能用這種方法來解決了。這時就需要檢查一下自己的makefile涉及到源文件、頭文件的地方是否出錯了,也有可能是其他的原因