MySQL一直没有修复这个bug,他们在2010年发布了一个叫作"utf8mb4"的字符集,MySQL的
"utf8mb4"是真正的"UTF-8"
-
下面我们调用MySQL的C API操作MySQL,在建表的时候其表的编码格式指定为utf8而不是utf8mb4,因此其只支持每个字符最多3个字节,然后向表中插入数据。并且调用mysql_set_character_set()函数将当前用户的默认字符集设置为utf8
-
在插入数据的时候(见下面的INSERT_SAMPLE_TABLE宏),其插入的第二个熙字占用4字节,因此下面程序的结果应该会出错
#include <stdio.h>
#include <stdlib.h>
#include <mysql.h>
#define DROP_SAMPLE_TABLE "DROP TABLE IF EXISTS utf8_tbl"
#define CREATE_SAMPLE_TABLE "CREATE TABLE utf8_tbl ( \
utf8_id INT UNSIGNED AUTO_INCREMENT, \
utf8_title VARCHAR(100) NOT NULL, \
PRIMARY KEY (utf8_id) \
)ENGINE=InnoDB DEFAULT CHARSET=utf8"
#define INSERT_SAMPLE_TABLE "INSERT INTO utf8_tbl(utf8_title) VALUES('????熙')"
#define SELECT_SAMPLE_TABLE "SELECT * FROM utf8_tbl"
#define DBNAME "unicode"
#define CHARSET "utf8"
int main()
MYSQL *mysql; //MySQL连接句柄
//初始化连接句柄
mysql = mysql_init(NULL);
if(mysql == NULL)
fprintf(stderr, "mysql_init failed, code: %d, reason: %s\n", mysql_errno(mysql), mysql_error(mysql));
return -1;
//连接MySQL服务端
if(mysql_real_connect(mysql, "localhost", "root", "123456", DBNAME, 0, NULL, 0) == NULL)
fprintf(stderr, "mysql_connect failed, code: %d, reason: %s\n", mysql_errno(mysql), mysql_error(mysql));
mysql_close(mysql);
return -1;
printf("Connection success\n\n");
//设置当前连接的默认字符集(此处设置为utf8)
if(mysql_set_character_set(mysql, CHARSET) != 0)
fprintf(stderr, "mysql_set_character_set failed, code: %d, reason: %s\n", mysql_errno(mysql), mysql_error(mysql));
mysql_close(mysql);
return -1;
//删除表
if(mysql_query(mysql, DROP_SAMPLE_TABLE) != 0)
fprintf(stderr, "drop table failed, code: %d, reason: %s\n", mysql_errno(mysql), mysql_error(mysql));
mysql_close(mysql);
return -1;
printf("drop table success\n\n");
//创建表
if(mysql_query(mysql, CREATE_SAMPLE_TABLE) != 0)
fprintf(stderr, "create table failed, code: %d, reason: %s\n", mysql_errno(mysql), mysql_error(mysql));
mysql_close(mysql);
return -1;
printf("create table success\n\n");
//向表中插入数据
if(mysql_query(mysql, INSERT_SAMPLE_TABLE) != 0)
fprintf(stderr, "insert failed, code: %d, reason: %s\n", mysql_errno(mysql), mysql_error(mysql));
mysql_close(mysql);
return -1;
printf("insert success, insert %lu rows\n\n", (unsigned long)mysql_affected_rows(mysql));
//查询数据(此处调用mysql_store_result一次性读取所有数据,然后再调用mysql_fetch_row逐行获取数据)
if(mysql_query(mysql, SELECT_SAMPLE_TABLE) != 0)
fprintf(stderr, "select failed, code: %d, reason: %s\n", mysql_errno(mysql), mysql_error(mysql));
mysql_close(mysql);
return -1;
//查询数据,将所有的结果保存到结果集中
MYSQL_RES *res;
res = mysql_store_result(mysql);
if(res == NULL)
fprintf(stderr, "mysql_store_result failed, code: %d, reason: %s\n", mysql_errno(mysql), mysql_error(mysql));
mysql_close(mysql);
return -1;
printf("select %lu rows\n", (unsigned long)mysql_num_rows(res));
//逐行获取数据
MYSQL_ROW sqlrow;
int columnNum = mysql_num_fields(res);
while((sqlrow = mysql_fetch_row(res)) != NULL)
//逐列获取数据
for(int i = 0; i < columnNum; ++i)
printf("%s\t", sqlrow[i]);
printf("\n");
//查询完成之后释放结果集
mysql_free_result(res);
mysql_close(mysql);
return 0;
- 下面是效果,在插入数据的时候出错了,因为在插入数据的时候第二个熙字其占用4个字节,超过了MySQL中utf8编码的最大值,因此会出错
- 现在我们修改程序,将表的格式设置为utf8mb4,当前用户的编码设置也设置为utf8mb4,然后再重新编译运行程序,那么就执行成功了
Nginx
- 如果在Nginx中使用中文可能会出现错误(例如页面中有中文)
- 可以在Nginx配置文件中加入下面的选项来设置UTF-8配置
- 例如下面是一个Nginx配置文件
server {
listen 8888;
# 设置为utf-8格式
charset utf-8;
server_name 192.168.221.141;
location / {
root /mnt/hgfs/ubuntu/vip/20191017-unicode/src/nginx;
index index.php index.html index.htm;
Redis
可以配置--raw选项来解决乱码问题,例如下面在连接时指定--raw