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

Oracle数据库里字符集那些事儿,实际用起来到底咋整才靠谱

说到Oracle数据库的字符集,这玩意儿就像是一个大家庭里定的“家规”,规定了这个家里所有人(也就是所有数据)说话写字必须用哪种语言和文字,你要是定了个“只能讲普通话”的规矩,那家里有人想说广东话或者闽南语,可能就乱套了,Oracle的字符集也是这个理儿,定不好或者用不对,轻则显示乱码,重则数据根本存不进去,非常头疼。

这事儿得从两个核心概念说起,一个是数据库的“字符集”,另一个是“国家字符集”,根据Oracle官方文档里的说法(Database Globalization Support Guide》),字符集是数据库的默认设置,它决定了你怎么存储数据,比如VARCHAR2、CHAR、CLOB这些类型的字段,都用这个字符集,而国家字符集是给NVARCHAR2、NCHAR、NCLOB这些类型准备的备用方案,你建数据库的时候,最主要、最需要操心的是那个默认的字符集。

那在实际用起来,到底咋整才靠谱呢?我总结了几条血泪教训。

Oracle数据库里字符集那些事儿,实际用起来到底咋整才靠谱

第一,也是最最最重要的一条:在创建数据库的那一刻,就要把字符集选对,而且要尽可能选一个“心胸宽广”的。 这就好比盖房子,地基打错了,后面想改就得拆楼,代价巨大,Oracle官方也明确说了,数据库字符集一旦创建,后期再想修改是非常复杂和危险的,虽然不是完全不可能,但过程堪比一场大手术,容易出问题,那选哪个算“心胸宽广”呢?早些年流行用ZHS16GBK,它能很好地支持简体中文,但现在更推荐使用AL32UTF8,为啥?因为AL32UTF8是Unicode字符集的一种实现,你可以把它理解成一个“世界语”字符集,地球上绝大部分的文字符号它都能装下,你今天可能只处理中文,保不齐明天就要存几个日文片假名,或者某个客户名字里带个“♬”这种特殊符号,如果你数据库是ZHS16GBK,碰到这些非中文字符就可能抓瞎,存进去变成问号“?”,而AL32UTF8就能轻松应对,只要不是有特别古老的系统兼容性要求,无脑选AL32UTF8,能给未来省去无数麻烦。

第二,你的客户端环境(比如你的应用程序服务器、你用的SQL开发工具)的字符集设置,必须和数据库服务器“对上暗号”。 Oracle数据库在处理数据时,会在客户端和服务器之间进行一次字符转换,如果两边的“家规”不一样,转换就会出岔子,导致乱码,数据库是AL32UTF8,你的一个应用程序连接过来,但这个程序所在的系统环境变量设成了GBK,那么当程序把一条中文数据发给数据库时,数据库可能会误以为这是GBK编码的字符,然后试图把它转换成AL32UTF8,这一转,乱码就产生了,确保应用服务器、客户端工具(如PL/SQL Developer)的NLS_LANG环境变量设置正确,至关重要,让它和数据库字符集保持一致,比如AMERICAN_AMERICA.AL32UTF8,是最稳妥的做法。

Oracle数据库里字符集那些事儿,实际用起来到底咋整才靠谱

第三,对于超长文本,比如小说内容、大段的评论,要谨慎选择字段类型。 这里就涉及到前面说的“国家字符集”了,VARCHAR2类型用的是数据库字符集,而NVARCHAR2类型用的是国家字符集,如果你建库时选的国家字符集是UTF8(或AL16UTF16),那么NVARCHAR2就能提供比某些数据库字符集更纯粹的Unicode支持,在一些特定历史版本的Oracle中,如果数据库字符集不是UTF系列,但你又想确保某些关键字段(比如需要国际化的产品名称、用户输入的自由文本)绝对不出现乱码,就可以考虑使用NVARCHAR2,如果你的数据库字符集本身就已经是AL32UTF8了,那么绝大多数情况下,直接用VARCHAR2和CLOB就足够了,因为AL32UTF8已经是很好的Unicode支持了。

第四,导入导出数据(exp/imp或数据泵expdp/impdp)时,字符集是重中之重。 Oracle的导出工具在写数据文件时,会记录下当时数据库的字符集信息,导入的时候,如果目标库的字符集和导出文件里记录的不一致,导入工具就会尝试做转换,这个转换能成功的前提是,目标库的字符集必须是导出库字符集的“超集”,比如说,从ZHS16GBK库导出数据,往AL32UTF8库导入,通常没问题,因为AL32UTF8完全包容ZHS16GBK,但反过来,从AL32UTF8往ZHS16GBK导入,那些超出GBK范围的字符(比如emoji表情)就肯定会丢失或变成乱码,在做数据迁移前,先用SQL(比如select * from nls_database_parameters where parameter='NLS_CHARACTERSET';)查清楚两边数据库的字符集,是避免白忙活的关键一步。

对付Oracle字符集,核心思想就是“预防大于治疗”,在项目一开始,就通盘考虑业务可能涉及的语言范围,为未来留出扩展余地,首选AL32UTF8,然后在各个环节,从应用连接到数据迁移,都时刻留意字符集设置的一致性,这样,才能让字符集这个问题真正变得“靠谱”起来,不给你添乱。