ACG狂人

其实我更爱姐汁...

封装MySQL时解决的两个字符集问题

在我开始封装MySQL C API时,真的没有想过居然会在字符集问题上连续卡壳,折腾了一下午+一晚上,终于搞定这些问题。下面记录一下我遇见的问题以及解决办法,以作备忘。
首先遇见的当然是中文乱码问题。这个问题相对来说资料比较多,文档写得应该也是很清楚的,但是我没心思看,靠猜搞定。我首先设置MySQL服务器的默认字符集为UTF8,并保证我操作的表中的列字符集也是UTF8,然后重启MySQL服务,并尝试用mysql_query("INSERT INTO TestTable VALUES('你好')")来写入,结果失败在预料之中。我猜可能可以使用类似"INSERT INTO TestTable VALUES('\0x2734\0x3432')"这样的方式写入中文,但这样太丑了,也没有实用价值,我坚决不会去用。我又尝试使用MultiByteToWideChar去做,甚至使用了Qt的QTextCodec去转换“你好”这两个字,结果依然失败。这就有些蹊跷了,我决定调用mysql_character_set_name()看看到底有没有正确的设置成UTF8格式,让我意料之外的是:结果是latin1,这难道是拉丁字符集??我查看了一下API函数的相关说明,发现这里获取到的是客户端链接的字符集,我突然觉得,也许MySQL可以自动的在客户端与服务器之间的字符集进行转化!说做就做,我查到了可以用mysql_options()或者mysql_set_character_name()函数来设置客户端链接字符集,但这两个函数用的时机分别在调用mysql_real_connect()之前或之后。我将客户端链接设置成gb2312字符集,这是VC中支持中文的标准字符集之一(另一个标准是UTF16,需要用wchar_t  wstring和常量字符串前的L),结果,当然是非常正确的插入中文啦,呵呵!
正当我觉得下面的封装肯定会顺汤顺水之时,在封装基本完成的时候,我发现控制台不能输出我从MySQL取出的中文了!这太奇怪了,输出英文就没有问题,而中文虽然的确被准确无误的读入了std::string中(通过单步调试和ofstream得到确认),然而输出到cout中却会出错。为什么文件流没问题,控制台流会出问题呢?我跟踪了代码,发现在fputc()函数中出现了问题。另一个奇特的地方,就是在mysql_init()函数被调用之前,cout可以正确输出中文,但调用之后就不能输出,iostate被赋予4值,即badbit。我求了一下google,发现sputc()中的一个_nolock_write()函数是msvcrtd.lib中的函数,晕了,我在单步调试中也发现就是这里有问题,确切的说,mysql_init()函数被调用后,_nolock_write()函数就会出错。哈哈,总结出了这些特点之后,我已经隐约猜到了是哪里的问题了,还记得前几日才写的blog里的东西,我由于想要将libmysql.lib换成mysqlclient.lib静态库,所以便禁掉了msvcrtd.lib库,我肯定这里面有关联。
到底是什么原因呢?我觉得,由于这个MySQL的SDK不是我自己编译的,mysqlclient.lib里面调用crt函数时,对字符集的本地化做了设置,由于是欧美的字符集设置,所以一旦我调用了mysqlclient.lib里的函数,就无法再显示中文了。
猜出了问题的根源,那么如何解决这个问题呢?我可以肯定的是,使用std::cout.imbue(std::locale())是行不通的,那么下面就是列出的几个办法:
1、使用人家编译好的动态库,libmysql.lib,并将libmysql.dll拷贝过来,由于动态库和你的程序共享crt dll,因此字符集设置应该会是一致的。
2、如果你还是想用静态库,可以考虑自己下载源码并编译一遍,这是根本的解决办法。
3、如果你可以自己编译,且想用mysqlclient.lib,那么就重新编译mysqlclient吧,动态静态都可以。不过官网上下载的编译好的mysqlclient.lib是静态的,不能使用。

我最终的解决办法是第1种,因为比较懒,不想自己再去编译了,呵呵。

posted on 2009-10-09 22:29 酿妹汁 阅读(1931) 评论(3)  编辑 收藏 引用 所属分类: C++

评论

# re: 封装MySQL时解决的两个字符集问题 2009-10-11 11:33 Jeff Chen

我在之前的项目里遇到过相同的问题。

解决方案是:将数据库的字符集都改为UTC8,并将服务器端和客户端的配置文件的字符集设置都改为UTC8。  回复  更多评论   

# re: 封装MySQL时解决的两个字符集问题 2010-12-23 10:58 天下

真有那么复杂吗?

欢迎去我的博客看看.有关于C操作Mysql这一块的.

不过C操作MYSQL没有mysql++操作方便.
特别是多线程环境.
  回复  更多评论   

# re: 封装MySQL时解决的两个字符集问题 2010-12-23 10:58 天下

真有那么复杂吗?

欢迎去我的博客看看.有关于C操作Mysql这一块的.

不过C操作MYSQL没有mysql++操作方便.
特别是多线程环境.  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理