当前位置:首页 > 问答 > 正文

Oracle数据库里中文显示问题和字符集那些事儿分析探讨

开始)

这篇文章主要想聊聊在使用Oracle数据库时,经常会遇到的一个让人头疼的问题:为什么我存进去的中文,查出来就变成了一堆问号“???”或者奇怪的乱码,后台”?这事儿十有八九跟字符集有关,咱们就掰开揉碎了说说这是怎么回事,尽量不用那些让人犯晕的专业术语。

咱们得明白一个最基础的道理:计算机本身不认识什么中文、英文,它只认识0和1,任何一个字符,无论是英文字母“A”,还是汉字“啊”,在计算机里存储的时候,都必须被转换成一个数字编号,这个“映射关系”就是字符集,你可以把字符集想象成一本巨大的密码本,里面规定了哪个字对应哪个号码。

Oracle数据库安装的时候,有一个非常关键的步骤就是选择字符集,这个选择就像是给整个数据库定下了一个“官方语言”环境,常见的字符集有几种:比如US7ASCII,这是最基础的,只支持英文字母、数字和一些符号,压根就没有中文汉字的编号,如果你不小心用了个只支持英文的字符集,却非要往里存中文,那数据库根本就不认识这个字,它没办法,只能用一个它认为是“未知字符”的标记来代替,这个标记通常就是问号“?”。

现在更常用的是支持多种语言的字符集,比如AL32UTF8,UTF-8是一个国际标准,它几乎包含了世界上所有文字的编号,中文自然不在话下,现在新建的Oracle数据库,强烈建议将字符集设置为AL32UTF8,这样可以一劳永逸地避免很多字符显示问题。

问题来了,是不是只要数据库用的是AL32UTF8,就万事大吉了呢?远远不是,这就要引出第二个关键点:环境编码,你的数据是从哪里来的?是从一个应用程序(比如一个用Java写的网站,或者用Python写的脚本)插入到数据库里的,这个应用程序在运行时,它自己也有一个认知文本的编码方式,同样,你用来查询数据库的工具,比如SQLPlus、SQL Developer或者PL/SQL Developer,它们显示文字的时候,也有自己的一套编码设置。

我们可以把整个过程想象成一场“传话游戏”,假设数据库的“官方语言”是普通话(AL32UTF8),你的应用程序(比如一个设置成四川话环境的程序)要告诉数据库一句话:“你好”,这个四川话程序用四川话的发音(比如它的环境编码是GBK)把“你好”这两个字“说”了出来,数据库这边呢,它只听普通话,如果它比较聪明,它能听懂一些方言,它会尝试把听到的四川话“翻译”成普通话再存起来,这个翻译过程,在技术上叫做“字符集转换”。

这里就是最容易出问题的地方了:

  1. 如果翻译错了(转换失败): 应用程序明明是用四川话(GBK)说的“你好”,但却告诉数据库:“我这是在用普通话(UTF-8)跟你交流哦!”数据库一听,以为对方说的是普通话,就不做翻译了,直接把听到的(其实是GBK编码的字节流)当成了普通话(UTF-8)的意思存了起来,结果存进去的就是乱码,等你再用一个能正常显示的工具去查询时,数据库把当初存错的那串“乱码”原样返回,显示出来自然就是“后台”这种看不懂的东西了。

  2. 如果听众听不懂(客户端不支持): 另一种情况是,数据正确地以普通话(UTF-8)存进了数据库,你用来查询的客户端工具(比如SQLPlus),它自己被设置成只能听懂广东话(比如ZHS16GBK),而且它还以为数据库跟它一样也说广东话,当数据库用普通话把“你好”读出来时,这个广东话客户端完全听不懂,只能胡乱猜测,显示出来的可能就是乱码。

总结一下,要保证中文显示正确,需要满足三个环节的编码一致或者能够正确转换:

  • 数据库字符集: 最好是AL32UTF8。
  • 客户端操作系统/应用程序的编码: 你的Java程序可以通过设置JVM参数-Dfile.encoding=UTF-8来确保程序内部使用UTF-8编码。
  • 客户端工具的编码设置: 比如在SQL Developer里,你需要手动设置一下环境的编码与数据库一致(通常是UTF-8)。

怎么查看和检查呢?这里简单提一下,你可以用SQL语句 SELECT * FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER = 'NLS_CHARACTERSET'; 来查看数据库的字符集,对于客户端,就需要根据不同的工具进行设置了。

如果不幸已经出现了乱码,补救起来比较麻烦,如果是问号“???”,那基本是数据在存入时就已经丢失了原始信息,很难恢复,如果是第二种情况那种奇怪的乱码,理论上有可能通过导出数据,再以正确的编码方式重新导入来修复,但过程比较复杂。

解决Oracle中文乱码问题的核心思路就是“对齐编码”,确保数据在“出发”(应用程序)、“仓储”(数据库)和“目的地”(查询客户端)这三个地方,使用的“语言”(字符集)是统一的,或者至少是能够被正确翻译的,事先做好规划,选择UTF-8作为统一标准,能省去未来无数的麻烦。 结束)

Oracle数据库里中文显示问题和字符集那些事儿分析探讨