简述
C++操作MySQL,添加中文宽字符数据到数据库中,出现了数据库中字符乱码。
测试环境
VS2013 + Mysql 5.6.45
Mysql 5.6.45安装包:
读取数据乱码问题:
vs项目下,默认编码Unicode,但我的数据库默认utf8,所以读取数据的时候中文乱码。
百度了一下,发现只要将utf8字符转成unicode字符即可,转换函数如下:
wchar_t* Utf8_2_Unicode(char* row_i)
{
int len = MultiByteToWideChar(CP_UTF8, 0, row_i, strlen(row_i), NULL, 0);
wchar_t *wszStr = new wchar_t[len + 1];
MultiByteToWideChar(CP_UTF8, 0, row_i, strlen(row_i), wszStr, len);
wszStr[len] = '\0';
return wszStr;
}
写入数据乱码
解决了读取出错后以为读取只要反向转换就行,但是把接收到的utf8字符转换成unicode后并不能行。
然后在网上各种百度,然后又各种类型转换编码转换人都弄晕了,总是围绕utf8转来转去,没有一点成效。
最后看了一个帖子,说要以gbk形式写入,在内心抱着极度怀疑的情况下试了一下,没想到竟然成功了。
其实这个帖子看了很多遍了,在心里默默的排除了一万遍没想到最后竟然它才是有用的。
方法很简单,只要在写入之前设置编码为gbk即可。
strcpy_s(sql, "set names gbk");
测试代码
wchar_t* Utf8_2_Unicode(char* row_i)
{
int len = MultiByteToWideChar(CP_UTF8, 0, row_i, strlen(row_i), NULL, 0);
wchar_t *wszStr = new wchar_t[len + 1];
MultiByteToWideChar(CP_UTF8, 0, row_i, strlen(row_i), wszStr, len);
wszStr[len] = '\0';
return wszStr;
}
void showError(const char * error)
{
cout << error << endl;
getchar();
}
int main()
{
MYSQL mysql;
MYSQL *connect;
//初始化MYSQL
connect = mysql_init(&mysql);
if (connect == NULL)
{
showError(mysql_error(connect));
return;
}
cout << "Init OK" << endl;
//连接到MYSQL
connect = mysql_real_connect(connect, "localhost", "root", "123456", "test", 3306, NULL, 0);
if (connect == NULL)
{
showError(mysql_error(connect));
return;
}
cout << "Connect OK" << endl;
char sql[256] = { 0 };
//将编码设置为gbk
strcpy_s(sql, "set names gbk");
if (mysql_query(connect, sql))
{
showError(mysql_error(connect));
return;
}
const char* sqlTable = "create table test(f_id int primary key auto_increment, m1 varchar(255), m2 varchar(20))";
mysql_query(connect, sqlTable);
//写入中文数据
strcpy_s(sql, "INSERT INTO test(m1, m2) VALUES('测试', 'Test')");
if (mysql_query(connect, sql))
{
showError(mysql_error(connect));
return;
}
cout << "Insert success!\n";
//设置编码格式utf8
strcpy_s(sql, "set names utf8");
int ret = mysql_query(connect, sql);
if (ret)
{
showError(mysql_error(connect));
return;
}
//读取中文数据
strcpy_s(sql, "SELECT * FROM test");
ret = mysql_query(connect, sql);
if (ret)
{
showError(mysql_error(connect));
return ;
}
else
{
//获取结果集
MYSQL_RES *res = mysql_store_result(connect);
if (mysql_num_rows(res) == NULL)
{
showError(mysql_error(connect));
return ;
}
int nfieldNum = mysql_num_fields(res);
MYSQL_ROW row;
//取出结果集
while (row = mysql_fetch_row(res))
{
wchar_t *m1, *m2;
//将字符由utf8专转为unicode
m1 = Utf8_2_Unicode(row[0]);
m2 = Utf8_2_Unicode(row[1]);
//MessageBox(NULL, m1, m2, NULL);
}
mysql_free_result(res);
}
mysql_close(connect);
getchar();
}
效果显示:
问题分析
VS2013开发工具默认编码格式为GBK
Mysql数据库编码格式为Utf8
Mysql 查看编码格式
mysql> show variables like 'character%';
+--------------------------+--------------------------------+
| Variable_name | Value |
+--------------------------+--------------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | utf8 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | latin1 |
| character_set_system | utf8 |
| character_sets_dir | D:\Setup\mysql\share\charsets\ |
+--------------------------+--------------------------------+
8 rows in set
分析
set names utf8之前,
character_set_client | gbk
character_set_connection| gbk
character_set_results | gbk
set names utf8之后,
character_set_client | utf8
character_set_connection| utf8
character_set_results | utf8
以下是部分摘录:
在客户端和服务器的连接处理中也涉及了字符集和校对规则变量。每一个客户端有一个连接相关的字符集和校对规则变量。
考虑什么是一个“连接”:它是连接服务器时所作的事情。客户端发送SQL语句,例如查询,通过连接发送到服务器。服务器通过连接发送响应给客户端,例如结果集。对于客户端连接,这样会导致一些关于连接的字符集和校对规则的问题,这些问题均能够通过系统变量来解决:
· 当查询离开客户端后,在查询中使用哪种字符集?
服务器使用character_set_client变量作为客户端发送的查询中使用的字符集。
· 服务器接收到查询后应该转换为哪种字符集?
转换时,服务器使用character_set_connection和collation_connection系统变量。它将客户端发送的查询从character_set_client系统变量转换到character_set_connection(除非字符串文字具有象_latin1或_utf8的引介词)。collation_connection对比较文字字符串是重要的。对于列值的字符串比较,它不重要,因为列具有更高的校对规则优先级。
· 服务器发送结果集或返回错误信息到客户端之前应该转换为哪种字符集?
character_set_results变量指示服务器返回查询结果到客户端使用的字符集。包括结果数据,例如列值和结果元数据(如列名)。
你能够调整这些变量的设置,或可以依赖默认值(这样,你可以跳过本章)。
有两个语句影响连接字符集:
SET NAMES ‘charset_name’
SET CHARACTERSETcharset_name
SET NAMES 'x’语句与这三个语句等价:
mysql>SETcharacter_set_client =x;
mysql>SETcharacter_set_results =x;
mysql>SETcharacter_set_connection =x;
所以说:
set names utf8指定了客户端和服务器之间传递字符的编码规则为UTF8。
修改MySql默认编码
MySql默认编码是Latin1,不支持中文,要想修改默认编码,需要修改my.ini文件
[client]增加default-character-set=utf8
[mysql]增加default-character-set=utf8
[mysqld]增加
character_set_server=utf8
init_connect=‘SET NAMES utf8’
cmd下操作mysql乱码需要注意cmd编码
查看当前代码页,如果当前代码页是GBK那么需要set names GBK才可以保证不乱码。
chcp 65001/936修改代码页。完美解决乱码问题。