Oracle数据库中文乱码问题及解决方法

正常安装 oracle 数据库后,不会出现乱码,因为 oracle 数据库在安装后会在注册表中 填入本地编码集,这个是根据你的电脑环境配置的,一般都是 SIMPLIFIED CHINESE_CHINA.ZHS16GBK 

 如果你安装成功后,运行 sqlplus 时就出现了问题,就像下图

Oracle数据库中文乱码问题及解决方法

 那么很不幸,这是你的 windows 问题,是Windows 控制台的 bug 详情 可以参考此处

推荐的解决方案是 使用旧版控制台 (虽然有点丑),但是可以使用 vscode 的终端来运行 sqlplus ,这样就比较美观,还可以接受。也可以使用 git bash 窗口里运行 sqlplus,就是字体有点小。

最推荐的方案是将 vscode 的终端配置为 git 的 bash ,然后在 vscode 的终端里学习数据库

当然如果你觉得重装系统也可以的话,也可以重装系统解决

 按照上述设置后,乱码就可以解决了


下面是关于我对 oracle 字符集问题,以及造成乱码原因的理解

 由于我的电脑很不幸,升级到了 Windows 的 那个版本,导致我使用 oracle 时遇到好多奇怪的问题,在网上查找解决方式一直不能完美解决我的问题,直到后面我发现是 cmd 的问题,我就放弃了,使用了旧版的控制台

关于 oracle 的字符集,我没有太深的去查阅资料,不过也看了许多别人发布的博客文章,也有一定的了解。在这里我只说明一下我理解的 oracle 数据库在储存数据与读出数据时编码的转换问题,我会说明数据怎么编码进入数据库,从数据库取出数据时如何解码显示在控制台或其他终端上。  此处我只说明 windows 的问题


  1.  在控制台的设置选项中,有一个活动代码页的选项,我的是936,代表简体中文,可以使用 chcp 命令查看。这个设置规定了 控制台对字符的 编码与解码 过程   (下面的流程为没有设置 NLS_LANG 环境变量的条件下)
  2. sqlplus 这个窗口也有活动代码页,和 cmd 保持一致。当我们在  sqlplus  输入数据,准备向数据库中插入数据时,sqlplus 窗口 会根据 活动代码页代表的字符集对数据进行编码,编码后送给 oracle ,oracle 会得到本地机器的编码(通过 注册表中 sqlplus 的 NLS_LANG ),此时送去的编码与告诉 oracle 的编码集是一致的(不一致会出现问题),然后 oracle 对 送来的编码 按照 读取到的编码集对数据解码,同时,oracle 内部存储也有一个字符集标准,按照内部的字符集对解码得到的数据再次编码 (如果内部编码集与本机机器的编码集不一致,就进行了编码转换)。
  3. 从数据库取出,选择数据时,是上述过程的逆过程,oracle 取出数据,按照内部的编码集解码为数据,然后根据机器的编码,再将数据编码为机器字符集的编码,然后送出。
  4. 接下来就是解码过程,sqlplus 会根据自己的活动代码页对编码进行解码,显示出来
  5. 建议本地使用的字符集保持和 oracle 数据库内部的编码集一致,这样不会进行编码转换(编码转换可能出现问题,因为编码集储存的字符容量可能有两个集合不相交的部分)

 根据上面的流程,以及 oracle 安装后会自动将本地机器的字符集设置在注册表中,而且没有设置环境变量 NLS_LANG

所以编码集和解码集相同,故不会出现乱码问题,如果不幸出现,就是开始说的机器问题

 下面说明一下 设置 NLS_LANG 环境变量后和上面没有设置的区别

机器设置 NLS_LANG 后,上述流程基本不变,只是 数据按照 sqlplus窗口 的活动代码页,oracle 解码时按照 环境变量NLS_LANG 设置的编码集解码,(从此处就能发现,如果活动代码页代表的字符集和 NLS_LANG 设置的不同,解码就会出现问题,会造成后面的乱码),解码后 oracle 按照内部字符集编码进行储存。                                              输出数据时 oracle 按照内部字符集解码,然后根据 NLS_LANG 对数据编码,送给 sqlplus,sqlplus 再按照 活动代码页解码显示


总之,sqlplus 窗口控制着数据的编码与解码,NLS_LANG 是用来告诉 oracle 本地机器使用的编码集

环境变量的 NLS_LANG 优先级比 注册表中 sqlplus 的 NLS_LANG 高

在我解决乱码的过程中,看了好多解决方法,慢慢也学到一些东西

有许多文章里让执行 select userenv('language') from dual;  来得到字符集,并进行一些设置

相信你看了上面的内容,应该知道了 得到的字符集其实就是你设置的,没有设置环境变量 NLS_LANG 时会得到注册表中的这个值,如果设置了 环境变量,返回的就是环境变量设置的值。

同时这个值也是数据送进 oracle 时, oracle 得到的本机字符集

最后的说明

 正常情况下  不需要  设置环境变量,也不需要修改注册表中的值

如果你永久修改了 cmd 的活动代码页,则需要将注册表中的 NLS_LANG 改为对应的字符集(或者设置环境变量)

建议:活动代码页代表的字符集 与 注册表里或者环境变量里设置的字符集 与  oracle 数据库存储使用的字符集  保持一致,这样是不会出现问题的(当然编码转换一般情况下也不会出现问题,除非你使用了极少见的字符)

但是至少要保证  活动代码页代表的字符集 与 注册表里或者环境变量里设置的字符集 一致(虽然不一致不一定会导致问题)


参考资料

  1. https://blog.csdn.net/zhang_yanchao/article/details/79092711

  2. https://blog.csdn.net/xingzhemoluo/article/details/39430487

  3. https://blog.csdn.net/zhougewang/article/details/69499918 

  4. https://www.cnblogs.com/xdouby/p/5666624.html