服务器架设笔记——httpd插件支持mysql字符集选择
? ? ? ? mysql數據庫默認的字符集是latin1。默認情況下,我們編譯的httpd插件是可以正常讀取該類型的數據庫,并且不會出現亂碼。但是,如果我們的數據庫變成其他格式,比如UTF8,那么默認讀取出來的數據就是亂碼,且無論我們怎么設置參數都不會起作用。(轉載請指明出于breaksoftware的csdn博客)
? ? ? ? 我們看一個utf8類型數據庫的例子,使用以下指令查看字符集
SHOW VARIABLES LIKE 'character_set_%';
? ? ? ? 通過character_set_database的值,我們可以得知該數據庫類型是utf8。這樣我們在讀取該數據庫時,便需要指定utf8字符集。在其他語言中,我們一般如此設置
“charset=utf8"
? ? ? ? 我們嘗試將這句話加入到連接數據庫的參數中
status = apr_dbd_open(driver, pool_db, "host=localhost;user=user_name;pass=password;dbname=database_name;charset=utf8", &handle);
? ? ? ? 這句api可以執行成功,但是讀取的結果還是亂碼!這很不科學,于是我瀏覽了下apr數據庫相關函數,發現沒有一個特定的接口可以設定字符集。可以想象apr-util庫只是對libmysql++-dev 復雜接口的封裝。那么存在一種可能:apr-util實現還不全面。我們閱讀apr_dbd_open的實現
struct {const char *field;const char *value;} fields[] = {{"host", NULL},{"user", NULL},{"pass", NULL},{"dbname", NULL},{"port", NULL},{"sock", NULL},{"flags", NULL},{"fldsz", NULL},{"group", NULL},{"reconnect", NULL},{NULL, NULL}};unsigned int port = 0;apr_dbd_t *sql = apr_pcalloc(pool, sizeof(apr_dbd_t));sql->fldsz = FIELDSIZE;sql->conn = mysql_init(sql->conn);if ( sql->conn == NULL ) {return NULL;}for (ptr = strchr(params, '='); ptr; ptr = strchr(ptr, '=')) {/* don't dereference memory that may not belong to us */if (ptr == params) {++ptr;continue;}for (key = ptr-1; apr_isspace(*key); --key);klen = 0;while (apr_isalpha(*key)) {/* don't parse backwards off the start of the string */if (key == params) {--key;++klen;break;}--key;++klen;}++key;for (value = ptr+1; apr_isspace(*value); ++value);vlen = strcspn(value, delims);for (i = 0; fields[i].field != NULL; i++) {if (!strncasecmp(fields[i].field, key, klen)) {fields[i].value = apr_pstrndup(pool, value, vlen);break;}}ptr = value+vlen;}if (fields[4].value != NULL) {port = atoi(fields[4].value);}if (fields[6].value != NULL &&!strcmp(fields[6].value, "CLIENT_FOUND_ROWS")) {flags |= CLIENT_FOUND_ROWS; /* only option we know */}if (fields[7].value != NULL) {sql->fldsz = atol(fields[7].value);}if (fields[8].value != NULL) {mysql_options(sql->conn, MYSQL_READ_DEFAULT_GROUP, fields[8].value);}
#if MYSQL_VERSION_ID >= 50013if (fields[9].value != NULL) {do_reconnect = atoi(fields[9].value) ? 1 : 0;}
#endif#if MYSQL_VERSION_ID >= 50013/* the MySQL manual says this should be BEFORE mysql_real_connect */mysql_options(sql->conn, MYSQL_OPT_RECONNECT, &do_reconnect);
#endifreal_conn = mysql_real_connect(sql->conn, fields[0].value,fields[1].value, fields[2].value,fields[3].value, port,fields[5].value, flags);
? ? ? ? 粗略讀了一下這段代碼,可以得出以下幾點判斷:
- apr_dbd_open內部使用mysql_real_connect連接數據庫
- apr_dbd_open可以解析的參數只有fields數組中定義的字段
- apr_dbd_open封裝了mysql_options函數用于設置相關參數
? ? ? ? 我們從mysql的開發文檔(http://dev.mysql.com/doc/refman/5.7/en/mysql-real-connect.html)中可以查閱到如下一句話
The user and passwd parameters use whatever character set has been configured for the MYSQL object. By default, this is latin1, but can be changed by calling mysql_options(mysql, MYSQL_SET_CHARSET_NAME, "charset_name") prior to connecting.
? ? ? ? 可以見得我們需要使用mysql_options,傳遞MYSQL_SET_CHARSET_NAME來設置字符集。但是通過對apr-util庫的通篇搜索,mysql_options只是在apr_dbd_open中被使用了,且還搜索不到MYSQL_SET_CHARSET_NAME。那么我們可以認定apr-util還沒實現”字符集選擇“的功能。我們需要自己手工修改代碼(/usr/src/apr-util-1.5.4/dbd/apr_dbd_mysql.c)
struct {const char *field;const char *value;} fields[] = {{"host", NULL},{"user", NULL},{"pass", NULL},{"dbname", NULL},{"port", NULL},{"sock", NULL},{"flags", NULL},{"fldsz", NULL},{"group", NULL},{"reconnect", NULL},{"charset", NULL},{NULL, NULL}};
? ? ? ? 先設定好需要解析的字段,再在mysql_real_connect之前插入
if (fields[10].value != NULL) {mysql_options(sql->conn, MYSQL_SET_CHARSET_NAME, fields[10].value);}
? ? ? ? 如此,重新編譯apr-util和httpd庫,我們的插件便可以支持數據庫字符集的選擇了。
總結
以上是生活随笔為你收集整理的服务器架设笔记——httpd插件支持mysql字符集选择的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 服务器架设笔记——多模块和全局数据
- 下一篇: 以金山界面库(openkui)为例思考和