zoukankan      html  css  js  c++  java
  • Oracle 字符集

    1.字符集查看方式;
    2.服务端、客户端字符集设置;
    3.乱码分析;

    1.字符集查看方式:
    1.1 通过 nls_database_parameters 视图查询数据库字符集(数据来源于props$):

    1 SQL> select parameter,value from nls_database_parameters where parameter like '%CHARACTER%';
    2 
    3 PARAMETER                      VALUE
    4 ------------------------------ ------------------------------
    5 NLS_NUMERIC_CHARACTERS         .,
    6 NLS_CHARACTERSET               AL32UTF8
    7 NLS_NCHAR_CHARACTERSET         AL16UTF16
    8 Elapsed: 00:00:00.02

    1.2 通过 nls_session_parameters 查询当前session 环境变量(数据来源于:X$NLS_PARAMETERS):
    SQL> select * from nls_session_parameters;

    1.3 通过v$nls_parameters 视图查询(数据来源于:X$NLS_PARAMETERS):

    1 SQL> select parameter,value from v$nls_parameters where parameter like '%CHARACTER%';
    2 
    3 PARAMETER                                                        VALUE
    4 ---------------------------------------------------------------- ------------------------------
    5 NLS_NUMERIC_CHARACTERS                                           .,
    6 NLS_CHARACTERSET                                                 AL32UTF8
    7 NLS_NCHAR_CHARACTERSET                                           AL16UTF16
    8 Elapsed: 00:00:00.01

    1.4 通过用户环境变量查询:

    1 SQL> select userenv('language') from dual;
    2 
    3 USERENV('LANGUAGE')
    4 ----------------------------------------------------
    5 AMERICAN_AMERICA.AL32UTF8
    6 Elapsed: 00:00:00.03

    获得的结果包括:语言(NLS_LANGUAGE)、地区(NLS_TERRITORY)、字符集(NSL_CHARACTERSET);

    2.服务端、客户端字符集设置:
    2.1 服务端字符集设置:
    2.1.1 新的字符集是旧的字符集超类:
    数据库创建时提供字符集设置,通常是操作系统平台字符集,也可以在创建数据库后修改字符集,但新的字符集必须支持旧的字符集(旧字符集的超集);
    修改前备份所有数据,修改字符集后导入数据到新字符集中;
    修改步骤:

     1 SQL> shutdown immediate
     2  SQL> startup nomount
     3  SQL> alter database mount exclusive;  --装载数据为专用的高级模式;
     4  SQL> alter system enable restricted session; --启用受限制的session模式
     5  SQL> alter system set job_queue_processes=0; --'maximum number of job queue slave processes' 设置工作队列的最大进程数为0
     6  SQL> alter system set aq_tm_processes=0;
     7  SQL> alter database open;
     8  SQL> alter database character set AL32UTF8; --新的字符集必须支持旧的字符集(旧字符集的超集),相关错误:(ORA-12712: new character set must be a superset of old character set)
     9  SQL> shutdown immediate
    10  SQL> startup

     重启后字符集改变:

    1  Verifying file header compatibility for 11g tablespace encryption..
    2 Verifying 11g file header compatibility for tablespace encryption completed
    3 SMON: enabling tx recovery
    4 Database Characterset is AL32UTF8
    5 No Resource Manager plan active
    6 replication_dependency_tracking turned off (no async multimaster replication found)
    7 WARNING: AQ_TM_PROCESSES is set to 0. System operation                     might be adversely affected.
    8 Completed: ALTER DATABASE OPEN

    2.1.2 新的字符集不是旧的字符集超类:
    如果新字符集不是旧字符集的超类,如从 WE8MSWIN1252  ==>AL328TF8,修改方式如下,测试环境(ORACLE 11GR2):

    SHUTDOWN IMMEDIATE;
    startup mount;
    ALTER SYSTEM ENABLE RESTRICTED SESSION;
    ALTER SYSTEM SET job_queue_processes =0;
    ALTER DATABASE OPEN;
    ALTER DATABASE CHARACTER SET INTERNAL_USE AL32UTF8;  
    SHUTDOWN IMMEDIATE;
    STARTUP ;

    在RAC环境中,设置时先停止所有节点上的数据库和实例,然后在单个节点上启动实例和数据库,设置 cluster_database=false,关闭数据库和实例,根据字符集继续2.1.1 或 2.1.2 的操作步骤,设置成功后,再设置 cluster_database=true,最后关闭节点上的数据库和实例,使用srvctl 启动所有节点上的实例和数据库:

    alter system set cluster_database=false scope=spfile;
    SHUTDOWN IMMEDIATE;
    #执行2.1.1 或 2.1.2的操作
    alter system set cluster_database=true scope=spfile;
    shutdown immediate;

    srvctl start database -d dbname #最后使用srvctl 启动所以节点数据库

     2.2 客户端字符集设置:

    当客户端连接服务端时读取环境变量NLS_LANG和其它环境变量,当设置了NLS_LANG 环境变量后,相关环境变量(NLS_LANGUAGE、NLS_TERRITORY)会因该变量的设置而变化,因为它们默认情况下都是源于NLS_LANG环境变量;其它的环境变量(NLS_DATE_FORMAT、NLS_TIMESTAMP_FORMAT、NLS_NUMBERIC_CHARACTERS..)会因NLS_TERRITORY变量的设置而变化;WINDOWS 平台上NLS_LANG环境变量被设置在注册表内,在我的机器中默认值是:SIMPLIFIED CHINESE_CHINA.ZHS16GBK,LINUX 平台上通过NLS_LANG设置,如未设置或安装时使用Oracle Universal Install 安装,NLS_LANG环境变量是不会被设置的,其默认值为:AMERICAN_AMERICA.US7ASCII;

    3.乱码分析:
    以当前的环境为例,我并未设置NLS_LANG 环境变量,数据库的字符码为:AMERICAN_AMERICA.AL32UTF8

    1 SQL> select userenv('language') from dual;
    2 
    3 USERENV('LANGUAGE')
    4 ----------------------------------------------------
    5 AMERICAN_AMERICA.AL32UTF8

    而操作系统的字符集是:

    1 [sywu@wusuyuan ~]$ locale
    2 LANG=zh_CN.UTF-8

    查询数据和插入数据都是乱码的:

     1 SQL> select * from tb_distree;
     2 
     3         ID NAME
     4 ---------- ------------------------------------------------------------------
     5          3 ??
     6          3 ??
     7          4 ??
     8          5 ??
     9 SQL> insert into tb_distree values(17,'德国');
    10 
    11 1 row created.

    从10046 trace 中已经可以清晰看出后台乱码

     1 SQL ID: 5naprsgt1dqj3
     2 108 Plan Hash: 0
     3 109 insert  into tb_distree
     4 110 values
     5 111 (18,'������')
     6 112 
     7 113 
     8 114 call     count       cpu    elapsed       disk      query    current        rows
     9 115 ------- ------  -------- ---------- ---------- ---------- ----------  ----------
    10 116 Parse        1      0.00       0.00          0          0          0           0
    11 117 Execute      1      0.02       0.02          0          1          5           1
    12 118 Fetch        0      0.00       0.00          0          0          0           0
    13 119 ------- ------  -------- ---------- ---------- ---------- ----------  ----------
    14 120 total        2      0.02       0.02          0          1          5           1
    15 121 
    16 122 Misses in library cache during parse: 1
    17 123 Optimizer mode: ALL_ROWS
    18 124 Parsing user id: 85
    19 125 
    20 126 Rows     Row Source Operation
    21 127 -------  ---------------------------------------------------
    22 128       0  LOAD TABLE CONVENTIONAL  (cr=1 pr=0 pw=0 time=0 us)
    23 129 

    但此时数据库的字符集是AMERICAN_AMERICA.AL32UTF8,只是没有设置NLS_LANG环境变量且机器本身的字符集与数据库字符集不一致,在官方文档中表明该环境变量在未设置时默认为:AMERICAN_AMERICA.US7ASCII,US7ASCII字符集本身不支持中文,保存数据时,数据库进行字符转换,从US7ASCII转换为AL32UTF8;

    1 SQL> select id,name,dump(name,'1016') from tb_distree;
    2 
    3         ID NAME       DUMP(NAME,'1016')
    4 ---------- ---------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    5          3 ??         Typ=1 Len=6 CharacterSet=AL32UTF8: e4,ba,91,e5,8d,97
    6          3 ??         Typ=1 Len=6 CharacterSet=AL32UTF8: e5,b9,bf,e4,b8,9c
    7          4 ??         Typ=1 Len=6 CharacterSet=AL32UTF8: e5,8c,97,e4,ba,ac
    8          5 ??         Typ=1 Len=6 CharacterSet=AL32UTF8: e5,9b,9b,e5,b7,9d
    9          18 ??????    Typ=1 Len=18 CharacterSet=AL32UTF8: ef,bf,bd,ef,bf,bd,ef,bf,bd,ef,bf,bd,ef,bf,bd,ef,bf,bd

    经尝试怎么转换都是乱码:

     1 SQL> select convert('中国','US7ASCII') from dual;
     2 
     3 CO
     4 --
     5 ??
     6 
     7 SQL> select convert(convert('中国','US7ASCII'),'AL32UTF8') FROM DUAL;
     8 
     9 CO
    10 --
    11 ??

    设置环境变量:

     1 [sywu@wusuyuan ~]$ export NLS_LANG=AMERICAN_AMERICA.AL32UTF8
     2 [sywu@wusuyuan ~]$ echo $NLS_LANG
     3 AMERICAN_AMERICA.AL32UTF8
     4 
     5 SQL> select * from tb_distree;
     6 
     7         ID NAME
     8 ---------- ----------
     9          3 云南
    10          3 广东
    11          4 北京
    12          5 四川
    13          6 重庆
    14          7 上海
    15          8 香港
    16         15 ������
    17         17 ������
    18         18 ������

    这样字符就显示正常了,但之前在没有设置环境变量NLS_LANG=AMERICAN_AMERICA.AL32UTF8之前插入的数据依旧是乱码;总结:当客户端和服务端字符集相同时,不存在字符集转换,数据直接保存数据;当客户端和服务端字符集不相同时,在设置了NLS_LANG环境变量(未设置默认值:AMERICAN_AMERICA.US7ASCII)时,保存或提前数据,数据库都要经过字符转换,正确一致的设置字符集可以提高数据库效率;

  • 相关阅读:
    C#--web中上传图片与浏览
    win通过ssh访问virtualbox虚拟中的debian
    【转】win10中下载安装mysql5.7
    [转发]centos7利用crontab定时检测杀死cpu使用率超过80%的进程
    MySQL 重要参数 innodb_flush_log_at_trx_commit 和 sync_binlog
    查询正在执行的sql语句
    php图片等比例缩放
    excel 导入 sqlserver 字符串被截取为255长度解决方案
    查询阻塞的sql
    centos7安装mariadb10遇到的问题解决
  • 原文地址:https://www.cnblogs.com/lanston/p/3755978.html
Copyright © 2011-2022 走看看