原因:Oracle数据库字符集和plsql客户端所使用的字符集不一致。
查询时,可能因为解码问题导致解出错误的字符。
也可能插入时就没有使用正确的字符集,解码时用utf-8自然也无法解出正确的字符。
环境变量 NLS_LANG 定义了客户端使用的语言、地域和字符集。这个变量影响客户端如何发送和接收数据。
定义一个系统环境变量:环境变变量名:NLS_LANG 环境变量值:AMERICAN_AMERICA.AL32UTF8
保证数据库字符集和这个一致。
转换过程:
客户端发送数据:客户端应用程序按照 NLS_LANG 指定的字符集将数据发送给数据库。
数据传输:数据通过网络传输到数据库服务器。
数据接收与转换:数据库接收到数据后,会将其从客户端字符集转换为数据库字符集。
存储数据:转换后的数据以数据库字符集存储在数据库中。
详细流程:
比如我们要插入数据 "一二三四五六" 时的转换流程。假设以下环境设置:
- 客户端字符集 :
AL32UTF8
(由NLS_LANG
指定) - 数据库字符集 :
ZHS16GBK
(由NLS_CHARACTERSET
指定)
1. 客户端发送数据
- 数据:"一二三四五六"
- 客户端字符集 :
AL32UTF8
客户端应用程序会将数据 "一二三四五六" 按照 AL32UTF8
字符集编码。AL32UTF8
是 UTF-8 字符集的一种,支持几乎所有的 Unicode 字符。
编码示例:
- "一" 的 UTF-8 编码是
E4B880
- "二" 的 UTF-8 编码是
E4B881
- "三" 的 UTF-8 编码是
E4B882
- "四" 的 UTF-8 编码是
E4B883
- "五" 的 UTF-8 编码是
E4B884
- "六" 的 UTF-8 编码是
E4B885
所以,数据 "一二三四五六" 在 AL32UTF8
字符集下的编码是:
E4B880 E4B881 E4B882 E4B883 E4B884 E4B885
2. 数据传输
数据通过网络以字节流的形式传输到数据库服务器。
3. 数据接收与转换
Oracle 数据库接收到数据后,会读取客户端的 NLS_LANG 设置,识别出客户端使用的字符集是 AL32UTF8。
会先将数据E4B880 E4B881 E4B882 E4B883 E4B884 E4B885
使用指定的字符集(AL32UTF8)进行解码,解码成字符"一二三四五六",之后再将其使用 ZHS16GBK
进行编码。ZHS16GBK
是 GBK 字符集的一种,支持简体中文字符。(实际上解码并没有解成一二三四五六,解码和编码是一步完成的,这么写是为了方便理解)
转换过程:
- 输入数据 :
E4B880 E4B881 E4B882 E4B883 E4B884 E4B885
- 目标字符集 :
ZHS16GBK
转换示例:
- "一" 的 GBK 编码是
D2BB
- "二" 的 GBK 编码是
B6E0
- "三" 的 GBK 编码是
C6DF
- "四" 的 GBK 编码是
CBCE
- "五" 的 GBK 编码是
D2D5
- "六" 的 GBK 编码是
D2D6
所以,数据 "一二三四五六" 在 ZHS16GBK
字符集下的编码是:
D2BB B6E0 C6DF CBCE D2D5 D2D6
4. 存储数据
最终将转换后的数据D2BB B6E0 C6DF CBCE D2D5 D2D6
存储在数据库中。
总结
- 客户端发送数据 :数据 "一二三四五六" 以
AL32UTF8
字符集编码,即E4B880 E4B881 E4B882 E4B883 E4B884 E4B885
。 - 数据传输:数据通过网络传输到数据库服务器。
- 数据接收与转换 :数据库接收到数据后,将其从
AL32UTF8
转换为ZHS16GBK
,即D2BB B6E0 C6DF CBCE D2D5 D2D6
。 - 存储数据 :转换后的数据以
ZHS16GBK
字符集存储在数据库中。