不出问题,数据库字符集是小事,一旦出问题,字符集问题将成为噩梦。(记录一次oracle字符集导致的乱码问题)

从长远的角度来看,新技术所节省下来的成本,并不会给生产者带来更高的利润,而是降低了产品的价格,使消费者受惠

                                                             《牛奶可乐经济学》

 

                                  

 

 

    今日一朋友联系说他们oracle数据库中表的中文数据都变成乱码了,需要帮忙查找为什么出现该问题。因对方数据库在外网,得到消息后,立马通过远程工具连接过去进行分析。

 

1,基本情况

    oracle数据库:两套

    源端数据库表中建立了触发器,对表的增、删、改操作进行监听,一旦操作,将会把对应数据写入中间表,然后后台任务不断读取中间表信息,往目标数据库写入数据。

    客户读取的是目标端数据库数据。

 

2,问题初步分析

    oracle数据库字符集一般在数据库创建过程中就会指定,字符集指定后,一般不建议再次进行修改(如若要修改,需要重启数据库)。现场数据库中中文数据突然乱码,可能由以下几种情况导致:

 

  1. 客户端字符集与服务器端字符集不一致,导致获取到的数据为乱码

  2. 服务器端字符集突然进行了修改,导致数据库中中文为乱码

  3. 源端同步数据库字符集与目标端字符集不一致,导致同步过来数据为乱码。

  4. 源端数据库采集的数据为乱码

 

3,问题处理

    根据客户提供表,查看数据,发现中文为乱码

select * from ***_***_result;(为了保护客户隐私,此处星号用代表字母) SERIAL          PRODUCT_NAME-201808-00446  澶ч娇杞?鎶辫酱绠辫閰?-201808-00446  澶ч娇杞?鎶辫酱绠辫閰?-201808-00446  澶ч娇杞?鎶辫酱绠辫閰?-201808-00446  澶ч娇杞?鎶辫酱绠辫閰?

    表中数据为乱码,第一时间,我想到客户端字符集,进行查看,发现字符集正常(配置了环境变量NLS_LANG)

select * from nls_instance_parameters;NLS_LANGUAGE  AMERICANNLS_TERRITORY  AMERICA

    

    于是我进行数据库server端字符集查看,可以看到服务端字符集为ZHS16GBK。

select * from nls_database_parameters;
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    BYTENLS_NCHAR_CONV_EXCP     FALSE
NLS_NCHAR_CHARACTERSET  AL16UTF16
NLS_RDBMS_VERSION       11.2.0.3.0

 

 

    目标端数据库字符集没问题,没办法,只能查看源端数据库字符集(源端数据库在不同网络),结果字符集也为ZHS16GBK:

 
select * from nls_database_parameters;
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.1.0

 

    看到两端数据库字符集一致,我顿时傻眼了,两端数据库字符集都一样,为什么客户会说数据库中中文字符乱码了呢?

 

    于是我想难道是有人突然动了数据库字符集,或者源端今日录入的数据为乱码?于是我登陆源端进行目标端乱码对应表:

 
select serial,product_name from ***_***_ZXJ.***_***_RESULT where serial='-201808-00446';(为了保护客户隐私,此处星号用代表字母)  
  SERIAL        PRODUCT_NAME
-201808-00446 大齿/装配
-201808-00446 大齿/装配

 

    结果源端数据库表数据显示没问题,查看oracle alert日志,发现源端也没人修改字符集。

 

    自此,只能一个解释了,那么就是目标端字符集有人动过,查看目标端alert日志,发现问题:

ALTER DATABASE DEFAULT TABLESPACE "USERS"
Completed: ALTER DATABASE DEFAULT TABLESPACE "USERS"
alter database character set INTERNAL_CONVERT AL32UTF8
Mon Aug 20 10:26:04 2018
Thread 1 advanced to log sequence 2 (LGWR switch)
  Current log# 2 seq# 2 mem# 0: D:\ORACLE\ORADATA\ORCL\REDO02.LOG
Mon Aug 20 10:26:06 2018
Updating character set in controlfile to AL32UTF8
Synchronizing connection with database character set information
Database Characterset is AL32UTF8
No Resource Manager plan active
WARNING: AQ_TM_PROCESSES is set to 0. System operation                     might be adversely affected.
Starting background process CJQ0
Completed: ALTER DATABASE OPEN
Tue Nov 27 22:41:44 2018
CJQ0 started with pid=16, OS id=9160 
Tue Nov 27 22:41:48 2018
ALTER DATABASE CHARACTER SET ZHS16GBK 
ORA-12712 signalled during: ALTER DATABASE CHARACTER SET ZHS16GBK ...
ALTER DATABASE CHARACTER SET INTERNAL_USE ZHS16GBK
Tue Nov 27 22:42:05 2018

 

    可以看到,2018年8月20日,数据库字符集为AL32UTF8,11月27日,字符集变为ZHS16GBK。

 

    那么为什么客户提到数据是突然变为乱码的呢,至此,我怀疑是因为客户之之前调用的是2018年11月27日之后的数据,因为源端与目标端字符集一致,所以没显示乱码。今日因为调取到2018年11月27日之前的数据,因之前字符集AL32UTF8,变为ZHS16GBK,所有中文为乱码(AL32UTF8为ZHS16GBK的父集)。为了验证,我查询了一个拥有时间字段的表,进行数据验证。

 

    最新数据,数据正常:

 
select name from ***_**_MRL where create_date>=to_date('2019-01-01','yyyy-mm-dd') order by create_date desc; (为了保护客户隐私,此处星号用代表字母)  
     NAME
Tc/M车II端点子

 

    历史数据,数据乱码:

select name from ***_**_MRL where create_date<=to_date('2018-01-01','yyyy-mm-dd') order by create_date desc;(为了保护客户隐私,此处星号用代表字母)  
     NAME
CCB-Tp杞is鐓ф槑瀹夎鍥?
CCB-Mc杞is鐓ф槑绯荤粺瀹夎鍥?
    至此,问题根源找到。

 

4,总结

    通过本案例可以看到:平常我们使用数据库或者进行数据库变更时,不会注意到字符集这个小小的配置项,就好像字符集对数据库没影响一样。但是,一旦出现问题,字符集引起的问题是致命的。任何数据库管理员对于生产系统数据库的改动,都须慎之又慎!

 

                                           欢迎大家关注以下公众号进行数据库方面知识探讨:

                                                                  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值