以文本方式查看主题 - 曙海教育集团论坛 (http://sun4.cn/bbs/index.asp) -- SQL Server数据库 (http://sun4.cn/bbs/list.asp?boardid=67) ---- 国际化使用UTF-8造成数据库MSSQL Server 2000/2005存储乱码的分析 (http://sun4.cn/bbs/dispbbs.asp?boardid=67&id=2528) |
-- 作者:wangxinxin -- 发布时间:2010-12-13 13:34:58 -- 国际化使用UTF-8造成数据库MSSQL Server 2000/2005存储乱码的分析 看了许多网上使用MSSQL Server 2000/2005使用UTF-8造成数据库存储乱码的描述,也说一下自己做的一个国际化项目的经验。
这个项目描述: 架构:VC++的ATL Server进行开发; 页面:web页面是UTF-8编码,CodePage=65001; 应用服务器程序:编译好的dll是Unicode编码; 操作系统:中文Windows 2003 Server; 数据库联接方式:OLEDB 数据库:中文MSSQL Sever2005,显示Codepage=936, 字段都是支持Unicode的nchar,nvarcha,nText; SELECT COLLATIONPROPERTY(\'Chinese_PRC_Stroke_CI_AI\', \'CodePage\') 936 ________________________________________________ 发现从Web页面提交的数据到数据后查询总是乱码,经过检查,发现保存的数据直接就是是UTF-8编码,其CodePage=65001,而数据默认显示支持的Unicode语言版本Codepage=936(即是简体中文),所以数据查询的就是乱码,想过两种方案: 1,怀疑是数据时UTF-8编码,而SQLServer是UCS-2 版本,相通过UTF-8-〉UCS-2转换,发现还是行不通,仍然乱码,此路不通; 2, 搜索了网络发现并没有现成的例子,经过测试中文系统使用Web页面为GB2312编码提交的数据到数据很正常,基于Windows2003是支持 Unicode(UCS-2),排除操作系统的问题,这个过程经过分析可以这么理解:936(Web页面编码GB2312)-〉Unicode(应用服务 器端)-〉Unicode(数据库OLEDB传输)-〉UCS-2(数据库)-〉自动转化为936(Unicode简体中文语言版本),而使用UTF-8 的Web页面这个过程就是:65001(Web页面编码UTF-8)-〉Unicode(应用服务器端)-〉Unicode(数据库OLEDB传输)-〉 UCS-2(数据库)-〉自动转化为936(Unicode简体中文语言版本),所以最后的使用数据分析查询器看到的就是乱码,最后确定的方案就是两种手 段:一是更改数据查询分析器的Codepage为65001,很显然当前的SQLServer没有这个功能(没找到?知道的告诉我);二是将前端的UTF -8转为GB2312编码,很显然这个最后成功了,这个过程程序还是保留了所有的多语言的特性,一位UTF-8-〉GB2312,这个过程是无损的(新的 验证会出现部分方块无法显示),因为是UTF-8->Unicode->GB2312. 总结: 1,MSSQL Server不支持UTF-8(Codepage=65001)直接显示,数据库查询的显示数据使用默认的Codepage,如简体中文版就是936,繁 体中文是950,韩文949等,因此从使用的Web页面UTF-8提交的数据自动转换为所用的Codepage显示,因此就是乱码,这个有待MS SQL Server进一步发展,因为现在Oracle和MySQL是可以支持直接UTF-8存储显示,国际化时请先将数据由UTF-8编码转化为MSSQL数据 库默认的编码,读写出来这个过程着相反进行转化,这个过程看起来会因为转化过程影响处理速度(抉择于国际化); 2,ASP/ASPX/JSP/PHP使用MSSQL Server编程支持UTF-8都会面临这样的问题,可以看看MSDN有关这个方面的解释 补充:根据测试和MSDN分析,将UTF-8转化为GB2312并不是很好的方案,这样会使包含韩文、阿拉伯文等等,这些都会变成问号,所以整个过程并不是很繁琐,简化一下: 写数据库:浏览器表单提交数据(UTF-8)(ANSI编码)-〉应用服务器端程序(进行UTF-8-〉Unicode)-〉MS SQL Server(自动转化为字符集936编码显示内容,但数据肯定是Unicode方式存储的);
读数据库:MS SQL Server(936 - Unicode)-〉应用服务器端程序(进行Unicode-〉UTF-8)-〉浏览器显示
注意:其他条件设置不变
两个使用的函数:
1,UTF8转化为Unicode,inline为了编译后更快运行,老用到了,返回字符串为了使用链式表达式
inline WCHAR *UTF8ToUnicode(const char *str) throw()
{ int i = MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,str,-1,NULL,0); WCHAR *strUnicode=new WCHAR[i]; MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,str,-1,strUnicode,i); return strUnicode; delete []strUnicode; } 一定要返回WCHAR 或wchar_t类型,否则有些字符就会变成“?”,Unicode(UCS-2)是2个字节宽
2,Unicode转化为UTF8,inline同上意义
inline char *UnicodeToUTF8(const WCHAR* pText) throw()
{ int i= WideCharToMultiByte(CP_UTF8 |