通常在我们的现实环境中,存在3个字符集设置。

第一: 客户端应用字符集(Client Application Character Set)

第二: 客户端NLS_LANG参数设置

第三: 服务器端,数据库字符集(Character Set)设置

我们说,一个字符在客户端应用(比如SQLPLUS,CMD,NOTEPAD等)中以怎样的字符显示取决于客户端操作系统,客户端能够显示怎样的字符,
我们就可以在应用中录入这些字符,至于这些字符能否在数据库中正常存储,就和另外的两个字符集设置紧密相关了。

在传输过程中,客户端NLS_LANG主要用于进行转换判断

如果NLS_LANG等于数据库字符集,则不进行任何转换直接把字符插入数据库

如果不同则进行转换,转换主要有两个任务

  • 如果存在对应关系,则把相应二进制编码经过映射后(这一步映射以后,所代表的字符可能发生转换)传递给数据库
  • 如果不存在对应关系,则传递一个替换字符(很多平台就是?)

数据库字符集,在和客户端NLS_LANG不同时,会把经过NLS_LANG转换的字符进行进一步处理

  • 对于?(即不存在对应关系的字符)直接以?形式存放入数据库
  • 对于其他字符,在NLS_LANG和数据库字符集之间进行转换后存入。

以下我们来看一下最为常见的字符集及乱码的产生:

1.当NLS_LANG字符集与数据库字符集不同,同时NLS_LANG不同于Server端字符集设置

在这种情况下,存在两种可能:

  • 客户端输入的字符在NLS_LANG中没有对应的字符,这时无法转换,NLS_LANG使用替换字符替代这些无法映射的字符(这一步转换在TTS中
    完成),在很多字符集中这个替代字符就是”?”
  • 当客户端的字符在NLS_LANG中对应了不同的字符时,传递给数据库以后发生转换,存储的是字符,但是已经丢失了元数据,数据库中
    的字符不再代表客户端的输入。而且这个过程不可逆,这也就是为什么很多时候在客户端输入的是正常的编码,查询之后会得到未知字符的原因。

我们通过上图来简单说明一下这个过程,当客户端在WE8ISO8859P15字符集时,输入欧元符号: €,这时客户端NLS_LANG和数据库端字符集不同,
进行第一次转换,客户端€符号编码是A4,在NLS_LANG转换时,A4对应了NLS_LANG中的‘¤’,这一步的转换产生了错误映射。由于数据库字符集不
同于NLS_LANG设置,这时进一步的转换发生了,存入数据库的编码变成了C2A4,虽然同NLS_LANG进行了正确的转换,但是客户端录入的数据已经
损坏或者丢失了。

我们可以用我们熟悉的字符集做一个简单的测试:

测试环境:

客户端应用为中文18030字符集

NLS_LANG设置为US7ASCII字符集

数据库CHARACTER SET为ZHS16GBK

c:/>set NLS_LANG=AMERICAN_AMERICA.US7ASCII
c:/>sqlplus eygle/eygle
SQL*Plus: Release 9.2.0.4.0 - Production on Tue Nov 4 01:19:57 2003
Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.
Connected to:
Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production
With the Partitioning, Oracle Label Security, OLAP and Oracle Data Mining options
JServer Release 9.2.0.4.0 - Production
SQL> insert into test values('测试');
1 row created.
SQL> select name,dump(name) from test;
NAME DUMP(NAME)
--------------------------------------------------
2bJT Typ=1 Len=4: 50,98,74,84
这时候我们发现,查询出来的是混乱的字符,我们把这些字符转换为2进制就是
110010   1100010   1001010   1010100
补全8位就是       00110010  01100010  01001010  01010100
我们把首位换成1   10110010  11100010  11001010  11010100
我们来看正确的存储:c:/>set nls_lang=AMERICAN_AMERICA.ZHS16GBK

c:/>sqlplus eygle/eygle

SQL*Plus: Release 9.2.0.4.0 - Production on Tue Nov 4 01:40:18 2003

Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.

Connected to:
Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production
With the Partitioning, Oracle Label Security, OLAP and Oracle Data Mining options
JServer Release 9.2.0.4.0 - Production

SQL> insert into test values('测试');

1 row created.

SQL> col dump(name) for a30
SQL> select name,dump(name) from test;

NAME DUMP(NAME)
---------- ------------------------------
测试 Typ=1 Len=4: 178,226,202,212

1 row selected.

我们把这个结果转换为2进制表示          10110010  11100010  11001010  11010100

这个结果正是我们前面乱码首位补全1后的结果。

这个测试说明在US7ASCII转换中文的时候除去了首位的 1,这样就丢失了元数据,导致乱码出现,NLS_LANG的转换作用由此可加一斑!


3. NLS_LANG和数据库字符集相同时
在这种情况下,数据库端对客户端传递过来的编码不进行任何转换(这样可以提高性能),直接存储进入数据库,那么这时候就存在和上面同样的问题,
如果客户端传递过来的字符集在数据库中有正确的对应就可以正确存储,如果没有,就会被替换字符置换成?,乱码就这样产生了。

如上图所示,当NLS_LANG和数据库字符集设置相同都为UTF8时,客户端的欧元符号的编码A4就不会经过任何转换就插入到数据库中,而在UTF8的数
据库中,A4代表的是一个非法字符。

我们来看一个简单的测试

测试环境:

客户端字符集应用为中文GB18030

客户端NLS_LANG为US7ASCII

数据库字符集为US7ASCII

我们知道这个时候,存入的数据,数据库不进行任何转换,在以下的测试中,我们看到中文在US7ASCII字符集下得以正确显示。

c:/>set nls_lang=AMERICAN_AMERICA.US7ASCII
c:/>sqlplus eygle/eygle
SQL*Plus: Release 9.2.0.4.0 - Production on Tue Nov 4 01:02:04 2003
Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.
Connected to:
Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production
With the Partitioning, Oracle Label Security, OLAP and Oracle Data Mining options
JServer Release 9.2.0.4.0 - Production
SQL> insert into test values('测试');
1 row created.
SQL> commit;
Commit complete.
SQL> select * from test;
NAME
----------
测试
1 row selected.
SQL> col dump(name) for a30
SQL> select name,dump(name) from test;
NAME       DUMP(NAME)
---------- ------------------------------
测试       Typ=1 Len=4: 178,226,202,212
1 row selected.
SQL> select * from nls_database_parameters;
PARAMETER                      VALUE
------------------------------ ----------------------------------------
NLS_LANGUAGE                   AMERICAN
NLS_TERRITORY                  AMERICA
NLS_CURRENCY                   $
NLS_ISO_CURRENCY               AMERICA
NLS_NUMERIC_CHARACTERS         .,
NLS_CHARACTERSET               US7ASCII
NLS_CALENDAR                   GREGORIAN
NLS_DATE_FORMAT                DD-MON-RR
NLS_DATE_LANGUAGE              AMERICAN
NLS_SORT                       BINARY
NLS_TIME_FORMAT                HH.MI.SSXFF AM
PARAMETER                      VALUE
------------------------------ ----------------------------------------
NLS_TIMESTAMP_FORMAT           DD-MON-RR HH.MI.SSXFF AM
NLS_TIME_TZ_FORMAT             HH.MI.SSXFF AM TZR
NLS_TIMESTAMP_TZ_FORMAT        DD-MON-RR HH.MI.SSXFF AM TZR
NLS_DUAL_CURRENCY              $
NLS_COMP                       BINARY
NLS_LENGTH_SEMANTICS           BYTE
NLS_NCHAR_CONV_EXCP            FALSE
NLS_NCHAR_CHARACTERSET         AL16UTF16
NLS_RDBMS_VERSION              9.2.0.4.0
20 rows selected.
SQL>

结语:

对于DBA来说,有一个很重要的原则就是:不要把你的数据库置于危险的境地!

这就要求我们,在进行任何可能对数据库结构发生改变的操作之前,先做有效的备份,很多DBA没有备份的操作中得到了惨痛的教训。

字符集问题的初步探讨-乱码的产生相关推荐

  1. 字符集问题的初步探讨

    字符集问题的初步探讨 Oracle全球支持(即Globalization Support)允许我们使用本地语言和格式来存储和检索数据.通过全球支持,Oracle可以支持多种语言及字符集,得以展示数据库 ...

  2. 初步探讨BitTorrent文件的结构

    初步探讨BitTorrent文件的结构 百度百科介绍: torrent文件本质上是文本文件,包含Tracker信息和文件信息两部分.Tracker信息主要是BT下载中需要用到的Tracker服务器的地 ...

  3. 在英语课堂中培养学生音素觉知的初步探讨(Phonemic Awareness)

    From: http://blog.sina.com.cn/s/blog_4e8bd3550100c3kk.html Phonemic Awareness (2008-11-14 20:17:04)转 ...

  4. SN-TOP架构的初步探讨——谈淘宝TOP平台的升级

    SN-TOP架构的初步探讨 --谈淘宝TOP平台的升级 文章全文将于12月10日发布,敬请关注!

  5. 解决mysql中表字符集gbk,列字符集Latin1,python查询乱码问题

    最近在公司碰到一个异常蛋疼的情况,mysql数据库中,数据库和表的字符集都是'gbk',但是列的字符集却是'latin1',于是蛋疼的事情出现了. 无论我连接字符串的`charset`设置为`gbk` ...

  6. oracle utf-8中文乱码,修改Oracle字符集为UTF-8 解决中文乱码 oracle

    很多情况下,遇到数据库查询数据中文乱码,一般都是字符集的问题,下面记录一下oracle字符集的查看方法,并提供UTF-8字符集的修改方式. 1.查看数据库字符集 以下操作均在sqlplus或客户端中执 ...

  7. 关于addEventListener和attachEvent的初步探讨

    关于addEventListener和attachEvent IE不对应addEventListener,只能使用attachEvent,所以首先需要判断你的浏览器对应的是哪个事件函数 if (win ...

  8. 初步探讨WPF的ListView控件(涉及模板、查找子控件)

    本文结合模板的应用初步介绍ListView的应用 一.Xaml中如何建立数据资源 大部分数据都会来自于后台代码,如何Xaml同样的建立数据源呢?比如建立一个学生List: 首先引入命名空间: xmln ...

  9. 有关七巧板复原的算法初步探讨

    按:家里面有个七巧板,自从拿出来之后,就再也没能复原,尝试了好几次,都失败. 后来想想能不能用程序试试呢.初步思路 1.七巧板表示法 由于积木不是简单矩形的组合,因此它的表示方法比较麻烦.表示不清楚, ...

最新文章

  1. yolov3安卓实现_重磅!MobileNet-YOLOv3来了(含三种框架开源代码)
  2. ubuntu/deepin常用软件清单(都是使用sudo apt-get install安装方式)
  3. 第8部分 管理磁盘存储
  4. jquery让页面滚动到底部
  5. .NET Core实战项目之CMS 第四章 入门篇-Git的快速入门及实战演练
  6. java切换jdk版本_切换JDK版本quick
  7. 用HTML5 Canvas为Web图形创建特效
  8. 电子政务概论-课程形成性考核册
  9. 配置HP LaserJet M1536dnf MFP打印机通过TCPIP共享多台计算机
  10. 此图片来自QQ空间,未经许可不可与引用
  11. 425_PICkit2烧写PIC18F4580 MCU
  12. Java 使用JavaMail通过Gmail发送电子邮件
  13. 都有哪些南北朝类毕业论文文献呢?
  14. 幼儿园实时监测控制系统的设计
  15. 怎样将PDF水印删除 PDF删除水印的小技巧
  16. NTT将在全球颇具影响力的技术盛会CES 2021上在线展出
  17. Voyager的Roles和Pemissions
  18. 利用Hackrf One进行GPS定位欺骗制作超级跑马机
  19. win10上安装两个ubuntu16.04系统分别安装在SSD和HHD
  20. AOP中的概念通知、切点、切面

热门文章

  1. python 装饰器 参数-python装饰器的详细解析
  2. python训练营免费领取-马哥教育官网-专业Linux培训班,Python培训机构
  3. python csv读取-python如何读取csv数据
  4. python安装包为什么这么小-python(x,y)安装好了为何还是加载不了包
  5. 2018python培训-2018python深度学习核心技术培训班
  6. python为什么中文要encoding-python 中文编码问题如何解决?
  7. python哪里下载import包-python import 自己的包
  8. LeetCode Reorder List
  9. [ZJOI2007]仓库建设(斜率优化)
  10. 聊聊微服务的服务注册与发现