Oracle nvarchar2存储特殊字符乱码问题

Oracle nvarchar2存储特殊字符乱码问题

这个问题研究了一天多,终于搞定了。

起因是业务需要存特殊字符'ø'到varchar2的字段中出现乱码,因为数据库字符集是ZHS16GBK。

简单测试了下,像'ø'之类的特殊。由于国家字符集是AL16UTF16,准备用nvarchar2(nvarchar2用的是国家字符集)存储特殊字符。

但是测试环境测试结果是就算用nvarchar2存,还是有乱码的情况。

重现如下:

[oracle@zkm ~]$ locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=
[oracle@zkm ~]$ echo $NLS_LANG
AMERICAN_AMERICA.AL32UTF8

11:22:28 SYS@zkm(451)> select userenv('language') from dual;

USERENV('LANGUAGE')
--------------------------------------------------------------------------------
AMERICAN_AMERICA.ZHS16GBK

Elapsed: 00:00:00.01
11:22:06 SYS@zkm(451)> create table zkm ( name1 varchar2(20),name2 nvarchar2(20));

Table created.

Elapsed: 00:00:01.39

11:30:12 SYS@zkm(451)> select * from NLS_DATABASE_PARAMETERS;

PARAMETER                                          VALUE
-------------------------------------------------- --------------------------------------------------
NLS_LANGUAGE                                       AMERICAN
NLS_TERRITORY                                      AMERICA
NLS_CURRENCY                                       $
NLS_ISO_CURRENCY                                   AMERICA
NLS_NUMERIC_CHARACTERS                             .,
NLS_CHARACTERSET                                   ZHS16GBK
NLS_CALENDAR                                       GREGORIAN
NLS_DATE_FORMAT                                    DD-MON-RR
NLS_DATE_LANGUAGE                                  AMERICAN
NLS_SORT                                           BINARY
NLS_TIME_FORMAT                                    HH.MI.SSXFF AM
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                                  11.2.0.4.0

20 rows selected.

Elapsed: 00:00:00.00
11:31:18 SYS@zkm(451)> insert into zkm values ('ø','ø');

1 row created.

Elapsed: 00:00:00.00
11:31:21 SYS@zkm(451)> commit;

Commit complete.

Elapsed: 00:00:00.00
11:31:26 SYS@zkm(451)> select * from zkm;

NAME1      NAME2
---------- ----------
?         ?           (这里是中文问号)

Elapsed: 00:00:00.00

比对中文问号和英文问号:

14:19:01 SYS@zkm(451)> select dump('?',1016) from dual union all select dump('',1016) from dual union all select dump('ø',1016) from dual;

DUMP('?',1016)
---------------------------------------------------------------------------------------------------------------------------
Typ=96 Len=1 CharacterSet=ZHS16GBK: 3f
Typ=96 Len=2 CharacterSet=ZHS16GBK: a3,bf
Typ=96 Len=2 CharacterSet=ZHS16GBK: a3,bf

Elapsed: 00:00:00.01

也就是说,在ZHS16GBK下,中文"?"和"ø"最后成了一样的效果,也就是"ø"乱码了。

这个很好理解,Linux OS将UTF8类型的"ø"通过sqlplus这个客户端送进去数据库中,然后数据库通过NLS_LANG环境变量了解到进来的"ø"是UTF8编码的,于是通过比对UTF8编码表和GBK编码表对应的"ø",将UTF8编码的"ø"转换成GBK的"ø"。

由于GBK不支持特殊字符"ø",在GBK编码表中不存在对应的编码,于是使用GBK编码表中的中文"?"编码替代,通过上边的dump可知为a3bf,这个就是乱码的原因。

我们可以dump表zkm的name1,由于name2字段为nvarchar类型,该类型不使用数据库字符集ZHS16GBK,而是使用国家字符集AL16UTF16,因此有如下结果:

14:38:24 SYS@zkm(87)> select dump(name1,1016) name1,dump(name2,1016) name2 from zkm;

NAME1                                              NAME2
-------------------------------------------------- --------------------------------------------------
Typ=1 Len=2 CharacterSet=ZHS16GBK: a3,bf           Typ=1 Len=2 CharacterSet=AL16UTF16: ff,1f

Elapsed: 00:00:00.00

可以知道,将"ø"insert进去表的name1,name2字段,确实变成了中文的"?" ,都是'a3bf'。

不过问题是nvarchar类型用的是AL16UTF16,为啥存不了"ø"??


网上找资料才发现,要通过加N告诉这个特殊字符是Unicode字符才行。

用法参考:

http://www.orafaq.com/wiki/NVARCHAR2

http://www.orafaq.com/wiki/NCHAR

于是:

15:35:30 SYS@zkm(1398)> select dump(N'?',1016) from dual union all select dump(N'',1016) from dual union all select dump(N'ø',1016) from dual;

DUMP(N'?',1016)
--------------------------------------------------------------------------------
Typ=96 Len=2 CharacterSet=AL16UTF16: 0,3f
Typ=96 Len=2 CharacterSet=AL16UTF16: ff,1f
Typ=96 Len=2 CharacterSet=AL16UTF16: ff,1f

Elapsed: 00:00:00.00
15:35:39 SYS@zkm(1398)> delete zkm;

1 row deleted.

Elapsed: 00:00:00.01
15:35:44 SYS@zkm(1398)> insert into zkm values ('ø',N'ø');

1 row created.

Elapsed: 00:00:00.00
15:36:05 SYS@zkm(1398)> commit;

Commit complete.

Elapsed: 00:00:00.00
15:36:44 SYS@zkm(1398)> select * from zkm; 

NAME1      NAME2
---------- ----------
?         ?

Elapsed: 00:00:00.00

加了N后还是发现,AL16UTF16下,中文"?"和"ø"还是一样的。

难道AL16UTF16不支持字符"ø"??不可能啊。

于是在新建了一个字符集为AL32UTF8的库,做上边同样建表的操作,然后插入数据,无论是varchar或者nvarchar都不会乱码啊,部分如下操作:

SQL> select dump(N'?',1016) from dual union all select dump(N'',1016) from dual union all select dump(N'ø',1016) from dual;

DUMP(N'?',1016)
------------------------------------------
Typ=96 Len=2 CharacterSet=AL16UTF16: 0,3f
Typ=96 Len=2 CharacterSet=AL16UTF16: ff,1f
Typ=96 Len=2 CharacterSet=AL16UTF16: 0,f8

SQL> select userenv('language') from dual;

USERENV('LANGUAGE')
----------------------------------------------------
AMERICAN_AMERICA.AL32UTF8

SQL> select dump(N'?',1016) from dual union all select dump(N'',1016) from dual union all select dump(N'ø',1016) from dual;

DUMP(N'?',1016)
------------------------------------------
Typ=96 Len=2 CharacterSet=AL16UTF16: 0,3f
Typ=96 Len=2 CharacterSet=AL16UTF16: ff,1f
Typ=96 Len=2 CharacterSet=AL16UTF16: 0,f8

SQL> select unistr('0F8') from dual;

UNIS
----
ø

从这个实验基本能够确定,Oracle将特殊字符"ø"存入数据库的时候,是先通过存为数据库字符集ZHS16GBK,然后再通过ZHS16GBK转为国家字符集AL16UTF16。

由于转ZHS16GBK的时候已经乱码,再次转AL16UTF16的时候就有问题了。

新库已经证明了国家字符集可以存该特殊字符了。

那么到底如何能够将特殊字符存进去nvarchar而不乱码,百度找不到于是只能MOS搜了,果然找到了..
实际上,环境变量ORA_NCHAR_LITERAL_REPLACE默认值为false,该变量表示任何从客户端传过来的NCHAR类型的字符先转换为数据库字符集,再转换为国家数据库字符集,而把该参数设为true后,从客户端传过来的NCHAR类型的字符直接转换为国家字符集存储,因此要想正确存储NCHAR字符集,最好得把该参数设为TRUE。

[oracle@zkm ~]$ export ORA_NCHAR_LITERAL_REPLACE=true
15:37:07 SYS@zkm(99)> delete from zkm;

1 row deleted.

Elapsed: 00:00:00.00
15:37:14 SYS@zkm(99)> insert into zkm values ('ø',N'ø');

1 row created.

Elapsed: 00:00:00.00
15:37:19 SYS@zkm(99)> commit;

Commit complete.

Elapsed: 00:00:00.00
15:37:22 SYS@zkm(99)> col name1 for a10
15:37:27 SYS@zkm(99)> col name2 for a10
15:37:27 SYS@zkm(99)> select * from zkm;

NAME1      NAME2
---------- ----------
?         ø

Elapsed: 00:00:00.00

由于name1为varchar类型本身不支持特殊字符乱码是正常的,而name2为nvarchar现在已经正常存取了。

开启会话,做10046。

执行sql,对应trace信息:

insert into zkm values ('ø',N'ø');
对应的trc信息:
*** 2021-08-18 16:03:01.812 WAIT #140175898804800: nam='SQL*Net message from client' ela= 24006178 driver id=1650815232 #bytes=1 p3=0 obj#=-1 tim=1629273781812848 CLOSE #140175898804800:c=9,e=9,dep=0,type=1,tim=1629273781812992 ===================== PARSING IN CURSOR #140175898795576 len=38 dep=0 uid=0 oct=2 lid=0 tim=1629273781814001 hv=1357752502 ad='ce798418' sqlid='fj1m2tx8fva5q' insert into zkm values ('U'0F8') END OF STMT PARSE #140175898795576:c=941,e=950,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,plh=0,tim=1629273781813995 EXEC #140175898795576:c=256,e=256,p=0,cr=1,cu=2,mis=0,r=1,dep=0,og=1,plh=0,tim=1629273781814387 STAT #140175898795576 id=1 cnt=0 pid=0 pos=1 obj=0 op='LOAD TABLE CONVENTIONAL (cr=1 pr=0 pw=0 time=195 us)' WAIT #140175898795576: nam='SQL*Net message to client' ela= 3 driver id=1650815232 #bytes=1 p3=0 obj#=-1 tim=1629273781814475 *** 2021-08-18 16:04:06.396 WAIT #140175898795576: nam='SQL*Net message from client' ela= 64582323 driver id=1650815232 #bytes=1 p3=0 obj#=-1 tim=1629273846396824 CLOSE #140175898795576:c=9,e=9,dep=0,type=0,tim=1629273846397035
select N'ø' from dual;

对应的trc信息:
PARSING
IN CURSOR #140175898795576 len=25 dep=0 uid=0 oct=3 lid=0 tim=1629273846398341 hv=1602785773 ad='f1c07ee8' sqlid='9rgvrkjgsj4gd' select U'0F8' from dual END OF STMT PARSE #140175898795576:c=1197,e=1208,p=0,cr=0,cu=2,mis=1,r=0,dep=0,og=1,plh=1388734953,tim=1629273846398339 EXEC #140175898795576:c=28,e=28,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=1388734953,tim=1629273846398525 WAIT #140175898795576: nam='SQL*Net message to client' ela= 2 driver id=1650815232 #bytes=1 p3=0 obj#=-1 tim=1629273846398588 FETCH #140175898795576:c=13,e=13,p=0,cr=0,cu=0,mis=0,r=1,dep=0,og=1,plh=1388734953,tim=1629273846398649 STAT #140175898795576 id=1 cnt=1 pid=0 pos=1 obj=0 op='FAST DUAL (cr=0 pr=0 pw=0 time=2 us cost=2 size=0 card=1)' WAIT #140175898795576: nam='SQL*Net message from client' ela= 384 driver id=1650815232 #bytes=1 p3=0 obj#=-1 tim=1629273846399149 FETCH #140175898795576:c=9,e=3,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=0,plh=1388734953,tim=1629273846399258 WAIT #140175898795576: nam='SQL*Net message to client' ela= 2 driver id=1650815232 #bytes=1 p3=0 obj#=-1 tim=1629273846399369

注意,正常存取需要满足3个条件

  1. 客户端的字符集需要支持目标字符
  2. 正确设置环境变量NLS_LANG
  3. 正确设置环境变量ORA_NCHAR_LITERAL_REPLACE

在这个案例中,sqlplus是在服务器Linux上的,因此sqlplus本身没有字符集所以依托Linux字符集为UTF8,而UTF8满足第一个条件。

另外,NLS_LANG=AMERICAN_AMERICA.AL32UTF8和Linux的UTF8一致是正确的。

最后ORA_NCHAR_LITERAL_REPLACE=TRUE控制了Oracle存Unicode行为。

需要注意的另外一点,由于我的Linux是远程通过SecureCRT工具连接的,所以对应CRT的会话的字符集要设置和Linux字符集一样:

也就是说如果使用windows上边的sqlplus客户端,该客户端用的是936也就是简体中文字符集。

那么即使NLS_LANG和ORA_NCHAR_LITERAL_REPLACE设置正确也会有问题,因为客户端使用936(简体中文)送进去特殊字符"ø"的时候就已经出问题了,936不支持"ø"。

C:Usersadmin>chcp
活动代码页: 936

C:Usersadmin>set nls_lang
NLS_LANG=AMERICAN_AMERICA.ZHS16GBK

C:Usersadmin>set ORA_NCHAR_LITERAL_REPLACE
ORA_NCHAR_LITERAL_REPLACE=TRUE

C:Usersadmin>sqlplus sys/zkm@192.168.1.152/zkm as sysdba

SQL*Plus: Release 11.2.0.4.0 Production on Wed Aug 18 17:07:28 2021

Copyright (c) 1982, 2013, Oracle.  All rights reserved.


Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL> select userenv('language') from dual;

USERENV('LANGUAGE')
----------------------------------------------------
AMERICAN_AMERICA.ZHS16GBK

SQL> delete zkm;

2 rows deleted.

SQL> insert into zkm values ('ø',N'ø');

1 row created.

SQL> commit;

Commit complete.

SQL> col name1 for a10
SQL> col name2 for a10
SQL> select * from zkm;

NAME1      NAME2
---------- ----------
?          ?

另外,plsqldev这个工具,对于N'ø'这类特殊字符存储进去nchar或者nvarchar2字段的时候,不需要设置ORA_NCHAR_LITERAL_REPLACE也可以成功正常存取。

对plsqdev的会话开启10046,然后执行sql可以看出区别:

查会话sid:

然后oracle使用sys登录对该会话做10046:

17:26:10 SYS@zkm(1264)> select a.sid,a.serial#,b.pid,b.spid from v$session a ,v$process b where a.sid=&sid and b.addr=a.paddr;
Enter value for sid: 904
old   1: select a.sid,a.serial#,b.pid,b.spid from v$session a ,v$process b where a.sid=&sid and b.addr=a.paddr
new   1: select a.sid,a.serial#,b.pid,b.spid from v$session a ,v$process b where a.sid=904 and b.addr=a.paddr

       SID    SERIAL#        PID SPID
---------- ---------- ---------- ------------------------------------------------------------------------
       904      19623        566 31314

Elapsed: 00:00:00.00
17:26:18 SYS@zkm(1264)> oradebug setospid 31314
Oracle pid: 566, Unix process pid: 31314, image: oracle@zkm
17:26:26 SYS@zkm(1264)> oradebug unlimit
Statement processed.
17:26:34 SYS@zkm(1264)> oradebug tracefile_name
/u01/app/oracle/diag/rdbms/zkm/zkm/trace/zkm_ora_31314.trc
17:27:08 SYS@zkm(1264)> oradebug event 10046 trace name context forever,level 12
Statement processed.

执行sql以及对应的trc信息:

select N'ø' from dual;

对应trc信息:

*** 2021-08-18 17:29:08.991
WAIT #140112422498592: nam='SQL*Net message from client' ela= 3971881 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629278948991660
CLOSE #140112422498592:c=35,e=35,dep=0,type=3,tim=1629278948991949
PARSE #140112422437616:c=42,e=42,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=1388734953,tim=1629278948992074
EXEC #140112422437616:c=31,e=31,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=1388734953,tim=1629278948992156
WAIT #140112422437616: nam='SQL*Net message to client' ela= 2 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629278948992214
WAIT #140112422437616: nam='SQL*Net message from client' ela= 432 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629278948992721
WAIT #140112422437616: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629278948992806
FETCH #140112422437616:c=75,e=75,p=0,cr=0,cu=0,mis=0,r=1,dep=0,og=1,plh=1388734953,tim=1629278948992867
WAIT #140112422437616: nam='SQL*Net message from client' ela= 834 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629278948993770
CLOSE #140112422437616:c=0,e=5,dep=0,type=3,tim=1629278948993881
PARSE #140112422396376:c=0,e=37,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=0,tim=1629278948993983
BINDS #140112422396376:
 Bind#0
  oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=00 csi=00 siz=48 off=0
  kxsbbbfp=7f6e770e3dd8  bln=22  avl=02  flg=05
  value=1
 Bind#1
  oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=00 csi=00 siz=0 off=24
  kxsbbbfp=7f6e770e3df0  bln=22  avl=02  flg=01
  value=10000
WAIT #140112422396376: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629278948994352
EXEC #140112422396376:c=374,e=352,p=0,cr=0,cu=0,mis=0,r=1,dep=0,og=1,plh=0,tim=1629278948994401

*** 2021-08-18 17:29:09.050
WAIT #140112422396376: nam='SQL*Net message from client' ela= 55803 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629278949050287
CLOSE #140112422396376:c=71,e=71,dep=0,type=3,tim=1629278949050553
PARSE #140112422498592:c=57,e=56,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=0,tim=1629278949050700
BINDS #140112422498592:
 Bind#0
  oacdty=01 mxl=4000(2000) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=01 csi=852 siz=4000 off=0
  kxsbbbfp=7f6e770e2698  bln=4000  avl=00  flg=05
WAIT #140112422498592: nam='SQL*Net message to client' ela= 2 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629278949051042
EXEC #140112422498592:c=343,e=342,p=0,cr=0,cu=0,mis=0,r=1,dep=0,og=1,plh=0,tim=1629278949051110
WAIT #140112422498592: nam='SQL*Net message from client' ela= 600 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629278949051801
CLOSE #140112422498592:c=19,e=19,dep=0,type=3,tim=1629278949051952
=====================
PARSING IN CURSOR #140112422489040 len=33 dep=0 uid=0 oct=3 lid=0 tim=1629278949052107 hv=102554608 ad='a8c18128' sqlid='awymr8831tqzh'
select unistr('0F8') from dual
END OF STMT
PARSE #140112422489040:c=81,e=80,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=1388734953,tim=1629278949052105
EXEC #140112422489040:c=24,e=24,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=1388734953,tim=1629278949052252
WAIT #140112422489040: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629278949052311
WAIT #140112422489040: nam='SQL*Net message from client' ela= 341 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629278949052710
WAIT #140112422489040: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629278949052794
FETCH #140112422489040:c=65,e=65,p=0,cr=0,cu=0,mis=0,r=1,dep=0,og=1,plh=1388734953,tim=1629278949052846
STAT #140112422489040 id=1 cnt=1 pid=0 pos=1 obj=0 op='FAST DUAL  (cr=0 pr=0 pw=0 time=2 us cost=2 size=0 card=1)'
WAIT #140112422489040: nam='SQL*Net message from client' ela= 13438 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629278949066415
PARSE #140112420550224:c=37,e=37,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=272002086,tim=1629278949066577
WAIT #140112420550224: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629278949066639
WAIT #140112420550224: nam='SQL*Net message from client' ela= 8714 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629278949075423
CLOSE #140112422489040:c=11,e=11,dep=0,type=0,tim=1629278949075532
CLOSE #140112420550224:c=7,e=8,dep=0,type=3,tim=1629278949075599
PARSE #140112422498592:c=38,e=37,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=0,tim=1629278949075705
BINDS #140112422498592:
 Bind#0
  oacdty=01 mxl=4000(2000) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=01 csi=852 siz=4000 off=0
  kxsbbbfp=7f6e770e2698  bln=4000  avl=00  flg=05
WAIT #140112422498592: nam='SQL*Net message to client' ela= 2 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629278949076087
EXEC #140112422498592:c=386,e=386,p=0,cr=0,cu=0,mis=0,r=1,dep=0,og=1,plh=0,tim=1629278949076150
WAIT #140112422498592: nam='SQL*Net message from client' ela= 23076 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629278949099319
CLOSE #140112422498592:c=39,e=39,dep=0,type=3,tim=1629278949099542
PARSE #140112422394472:c=54,e=54,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=0,tim=1629278949099686
BINDS #140112422394472:
 Bind#0
  oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=00 csi=00 siz=24 off=0
  kxsbbbfp=7f6e770e3620  bln=22  avl=00  flg=05
 Bind#1
  oacdty=01 mxl=32767(32512) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=01 csi=852 siz=32767 off=0
  kxsbbbfp=7f6e77105000  bln=32767  avl=00  flg=05
 Bind#2
  oacdty=01 mxl=32767(32512) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=01 csi=852 siz=32767 off=0
  kxsbbbfp=7f6e77115000  bln=32767  avl=00  flg=05
 Bind#3
  oacdty=01 mxl=32767(32512) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=01 csi=852 siz=32767 off=0
  kxsbbbfp=7f6e77125000  bln=32767  avl=00  flg=05
 Bind#4
  oacdty=01 mxl=32767(32512) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=01 csi=852 siz=32767 off=0
  kxsbbbfp=7f6e77135000  bln=32767  avl=00  flg=05
 Bind#5
  oacdty=01 mxl=32767(32512) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=01 csi=852 siz=32767 off=0
  kxsbbbfp=7f6e76fc5000  bln=32767  avl=00  flg=05
 Bind#6
  oacdty=01 mxl=32767(32512) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=01 csi=852 siz=32767 off=0
  kxsbbbfp=7f6e76fd5000  bln=32767  avl=00  flg=05
 Bind#7
  oacdty=01 mxl=32767(32512) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=01 csi=852 siz=32767 off=0
  kxsbbbfp=7f6e76fe5000  bln=32767  avl=00  flg=05
 Bind#8
  oacdty=01 mxl=32767(32512) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=01 csi=852 siz=32767 off=0
  kxsbbbfp=7f6e76ff5000  bln=32767  avl=00  flg=05
 Bind#9
  oacdty=01 mxl=32767(32512) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=01 csi=852 siz=32767 off=0
  kxsbbbfp=7f6e77005000  bln=32767  avl=00  flg=05
 Bind#10
  oacdty=01 mxl=32767(32512) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=01 csi=852 siz=32767 off=0
  kxsbbbfp=7f6e77015000  bln=32767  avl=00  flg=05
WAIT #140112422394472: nam='SQL*Net message to client' ela= 3 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629278949100916
EXEC #140112422394472:c=1176,e=1219,p=0,cr=0,cu=0,mis=0,r=1,dep=0,og=1,plh=0,tim=1629278949100977
insert into zkm values ('ø',N'ø');

trc对应信息:

*** 2021-08-18 17:30:47.999
WAIT #140112422498592: nam='SQL*Net message from client' ela= 52681224 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629279047999859
CLOSE #140112422498592:c=38,e=37,dep=0,type=3,tim=1629279048000109
PARSE #140112422437616:c=44,e=44,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=1388734953,tim=1629279048000238
EXEC #140112422437616:c=33,e=33,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=1388734953,tim=1629279048000327
WAIT #140112422437616: nam='SQL*Net message to client' ela= 2 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629279048000392
WAIT #140112422437616: nam='SQL*Net message from client' ela= 387 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629279048000851
WAIT #140112422437616: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629279048000949
FETCH #140112422437616:c=51,e=51,p=0,cr=0,cu=0,mis=0,r=1,dep=0,og=1,plh=1388734953,tim=1629279048000987
WAIT #140112422437616: nam='SQL*Net message from client' ela= 556 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629279048001607
CLOSE #140112422437616:c=0,e=6,dep=0,type=3,tim=1629279048001681
PARSE #140112422396376:c=0,e=37,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=0,tim=1629279048001789
BINDS #140112422396376:
 Bind#0
  oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=00 csi=00 siz=48 off=0
  kxsbbbfp=7f6e770e3dd8  bln=22  avl=02  flg=05
  value=1
 Bind#1
  oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=00 csi=00 siz=0 off=24
  kxsbbbfp=7f6e770e3df0  bln=22  avl=02  flg=01
  value=10000
WAIT #140112422396376: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629279048002186
EXEC #140112422396376:c=323,e=374,p=0,cr=0,cu=0,mis=0,r=1,dep=0,og=1,plh=0,tim=1629279048002241
WAIT #140112422396376: nam='SQL*Net message from client' ela= 64591 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629279048066901
CLOSE #140112422396376:c=38,e=39,dep=0,type=3,tim=1629279048067161
PARSE #140112422498592:c=64,e=63,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=0,tim=1629279048067343
BINDS #140112422498592:
 Bind#0
  oacdty=01 mxl=4000(2000) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=01 csi=852 siz=4000 off=0
  kxsbbbfp=7f6e770e2698  bln=4000  avl=00  flg=05
WAIT #140112422498592: nam='SQL*Net message to client' ela= 3 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629279048067765
EXEC #140112422498592:c=440,e=439,p=0,cr=0,cu=0,mis=0,r=1,dep=0,og=1,plh=0,tim=1629279048067887
WAIT #140112422498592: nam='SQL*Net message from client' ela= 449 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629279048068474
CLOSE #140112422498592:c=13,e=14,dep=0,type=3,tim=1629279048068573
=====================
PARSING IN CURSOR #140112422489040 len=45 dep=0 uid=0 oct=2 lid=0 tim=1629279048069996 hv=1995508800 ad='aa58b168' sqlid='487qtctvg2320'
insert into zkm values ('?',unistr('0F8'))
END OF STMT
PARSE #140112422489040:c=1310,e=1363,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,plh=0,tim=1629279048069995
EXEC #140112422489040:c=364,e=364,p=0,cr=1,cu=2,mis=0,r=1,dep=0,og=1,plh=0,tim=1629279048070521
STAT #140112422489040 id=1 cnt=0 pid=0 pos=1 obj=0 op='LOAD TABLE CONVENTIONAL  (cr=1 pr=0 pw=0 time=294 us)'
WAIT #140112422489040: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629279048070653

*** 2021-08-18 17:30:48.083
WAIT #140112422489040: nam='SQL*Net message from client' ela= 13060 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629279048083757
CLOSE #140112422489040:c=9,e=9,dep=0,type=0,tim=1629279048083949
PARSE #140112422498592:c=46,e=45,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=0,tim=1629279048084075
BINDS #140112422498592:
 Bind#0
  oacdty=01 mxl=4000(2000) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=01 csi=852 siz=4000 off=0
  kxsbbbfp=7f6e770e2698  bln=4000  avl=00  flg=05
WAIT #140112422498592: nam='SQL*Net message to client' ela= 2 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629279048084343
EXEC #140112422498592:c=257,e=257,p=0,cr=0,cu=0,mis=0,r=1,dep=0,og=1,plh=0,tim=1629279048084389
WAIT #140112422498592: nam='SQL*Net message from client' ela= 18285 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629279048102755
CLOSE #140112422498592:c=32,e=32,dep=0,type=3,tim=1629279048102955
PARSE #140112422394472:c=44,e=45,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=0,tim=1629279048103082
BINDS #140112422394472:
 Bind#0
  oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=00 csi=00 siz=24 off=0
  kxsbbbfp=7f6e770e3620  bln=22  avl=00  flg=05
 Bind#1
  oacdty=01 mxl=32767(32512) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=01 csi=852 siz=32767 off=0
  kxsbbbfp=7f6e77105000  bln=32767  avl=00  flg=05
 Bind#2
  oacdty=01 mxl=32767(32512) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=01 csi=852 siz=32767 off=0
  kxsbbbfp=7f6e77115000  bln=32767  avl=00  flg=05
 Bind#3
  oacdty=01 mxl=32767(32512) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=01 csi=852 siz=32767 off=0
  kxsbbbfp=7f6e77125000  bln=32767  avl=00  flg=05
 Bind#4
  oacdty=01 mxl=32767(32512) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=01 csi=852 siz=32767 off=0
  kxsbbbfp=7f6e77135000  bln=32767  avl=00  flg=05
 Bind#5
  oacdty=01 mxl=32767(32512) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=01 csi=852 siz=32767 off=0
  kxsbbbfp=7f6e76fc5000  bln=32767  avl=00  flg=05
 Bind#6
  oacdty=01 mxl=32767(32512) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=01 csi=852 siz=32767 off=0
  kxsbbbfp=7f6e76fd5000  bln=32767  avl=00  flg=05
 Bind#7
  oacdty=01 mxl=32767(32512) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=01 csi=852 siz=32767 off=0
  kxsbbbfp=7f6e76fe5000  bln=32767  avl=00  flg=05
 Bind#8
  oacdty=01 mxl=32767(32512) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=01 csi=852 siz=32767 off=0
  kxsbbbfp=7f6e76ff5000  bln=32767  avl=00  flg=05
 Bind#9
  oacdty=01 mxl=32767(32512) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=01 csi=852 siz=32767 off=0
  kxsbbbfp=7f6e77005000  bln=32767  avl=00  flg=05
 Bind#10
  oacdty=01 mxl=32767(32512) mxlc=00 mal=00 scl=00 pre=00
  oacflg=01 fl2=1000000 frm=01 csi=852 siz=32767 off=0
  kxsbbbfp=7f6e77015000  bln=32767  avl=00  flg=05
WAIT #140112422394472: nam='SQL*Net message to client' ela= 2 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1629279048104189
EXEC #140112422394472:c=1067,e=1126,p=0,cr=0,cu=0,mis=0,r=1,dep=0,og=1,plh=0,tim=1629279048104261

至此。

参考文档

Storing And Retrieving Data Into NVARCHAR2 Columns Explained With Test Case (文档 ID 2311604.1)
Writing Buffer Data With DBMS_OUTPUT.PUT_LINE Results in an Upside Down Question Mark with Multibyte Data Stored in an NVARCHAR2 Column Type (文档 ID 1538753.1)
The National Character Set ( NLS_NCHAR_CHARACTERSET ) in Oracle 9i, 10g , 11g and 12c (文档 ID 276914.1)
再论Oracle字符集

http://www.orafaq.com/wiki/NVARCHAR2

http://www.orafaq.com/wiki/NCHAR

原文地址:https://www.cnblogs.com/PiscesCanon/p/15157506.html