mtk 存储过程迁移汉字乱码问题处理--NLS_LANG 不一定要跟数据库的字符集相同
mtk 解决存储过程乱码问题
| 数据库及版本 | 字符集 | |
|---|---|---|
| 源库 | ORACLE 19.19 | 字符集 |
| 目标库 | MogDB 5.0.5 | ZHS16GBK |
先看 MTK 的数据库迁移报告汇总页面
开始时间是 2024-04-01 09:43:50 结束时间: 2024-04-02 16:55:29 ,历经 1天7小时,数据2.7T左右。
存储过程总共 164 个,失败了 90个。
点击查看详情,可以看到它的报错是:
失败原因:
code: 3F001 msg: schema “xxxxx” does not exist Line: 14 Position: 465
可以看到 out xxxxx.refCursor 这个是个包的名称,这里 mtk识别为schema的名称,这不是关键因素,继续查看,发现大部分存储过程都是汉字是乱码。
但是单独通过工具导出的存储过程汉字是正常的。
也就是 mtk 在获取存储过程的时候编码有问题。
注意 mtk 的字符集的设置有两个,一个是数据库的 charset,一个是客户端的 clientCharset。
根据 https://docs.mogdb.io/zh/mtk/v2.0/mtk-config#clientcharset
clientCharset
类型: string
描述: 针对数据库编码转换场景使用,一般情况下不需要设置.
- 主动配置下会检查源和目标是否一致,不一致则同步源设置,一致不处理
- 默认根据源字符集进行设置,尽量减少转码次数。 如源Oracle是ZHS16GBK则以GBK读取,目标端以GBK插入,如果目标端是GBK则不需要转码,是UTF8则在数据库内核层转码不在驱动层转码
如 Oracle ZHS16GBK 编码迁移到 openGauss UTF8. 遇到
ORA-29275: partial multibyte character.
还有一个是 :charset
charset
类型: string
描述: 数据库字符集.
默认不用配置,连接数据库查询.
可选值:
- gbk
- utf8
的描述,这俩参数很强大,可以不用设置,会自动判断,但是在实施的过程会发现,存储过程的汉字会乱码。常存储过程是通过 dba_source 来获取的,检查部署 mtk 的主机的 NLS_LANG 设置为空,通过sqllus 查询 dba_source发现是乱码,手工设置为 gbk,也是乱码,后来设置为 utf8 之后,查询出来的dba_source 正常。同时也设置了xshell终端的字符集等,查询 dba_source 也是乱码,只有设置 NLS_LANG 为 utf8,查询正常。
1 | export NLS_LANG=AMERICAN_AMERICA.AL32UTF8 |
为了确保 mtk 获取的存储过程不是乱码,建议在终端设置 NLS_LANG参数(NLS_LANG 不一定要跟数据库的字符集相同,见后面的oracle 官方文章的 关于 NLS_LANG 的常见误解:将 NLS_LANG 设置为数据库的字符集有可能正确,但大多数情况下都是不正确的。请勿假设 NLS_LANG 必须与数据库字符集相同。事实往往并非如此。)之后,
如何检测呢,我这边测试就是通过sqlplus 查询 dba_source 如果汉字不乱码,然后执行mtk就正常。
源端 ORACLE 数据库的字符集是ZHS16GBK,但是 NLS_LANG 设置为 AMERICAN_AMERICA.AL32UTF8 是可以解决。设置为其他字符集比如跟数据库相同的字符集 ZHS16GBK 也是无法解决的。
之前总认为 NLS_LANG 的设置要跟数据库的字符集相同,后来查询资料发现这是错误的。https://www.oracle.com/cn/database/technologies/faq-nls-lang.html
关于 NLS_LANG 的常见误解
- 将 NLS_LANG 设置为数据库的字符集有可能正确,但大多数情况下都是不正确的。请勿假设 NLS_LANG 必须与数据库字符集相同。事实往往并非如此。
- 使用 NLS_LANG 参数定义字符集不会更改客户端的字符集。这是为了让 Oracle 知道您在客户端上所使用的字符集,以便 Oracle 可以做出正确的转换。如果您使用不同的 NLS_LANG 设置,这并不能更改客户端的字符集!
- 如果未在客户端上设置 NLS_LANG,则它将使用服务器的 NLS_LANG。同样,这可能是不正确的!例如,如果 Oracle 安装程序未填充 NLS_LANG,并且该参数没有另行设置,则其默认值为 AMERICAN_AMERICA.US7ASCII。语言是 AMERICAN,区域是 AMERICA,字符集是 US7ASCII。
- 设置 NLS_LANG 的 LANGUAGE 和 TERRITORY 参数与在数据库中存储字符的能力无关。如果将 NLS_LANG 设置为 JAPANESE_JAPAN.WE8MSWIN1252,由于 WE8MSWIN1252 不支持日语字符,因此不能存储日语。但是,将 NLS_LANG 设置为 AMERICAN_AMERICA.JA16SJIS 则可以存储日语,只要所输入的数据确实是 JA16SJIS,而且数据库也使用可以存储日语的字符集(如 UTF8 或 JA16SJIS)。
经过 设置之后,重新单独跑了mtk的存储过程,汇总页面有一些清爽了。接近 100%成功,其中1个识别和警告是源端数据库就是失效的存储过程。
以上的乱码应该不是 MTK 的问题,以上不设置的时候 sqlplus 也是乱码,设置了之后,sqlplus 不是乱码之后,mtk 的结果也不是乱码。关于 NLS_LANG 的知识,待日后补充。
附件:
*Table C-1 NLS_LANG Parameter Values*
| Operating System Locale | NLS_LANG Value |
|---|---|
| Arabic (U.A.E.) | ARABIC_UNITED ARAB EMIRATES.AR8MSWIN1256 |
| Bulgarian | BULGARIAN_BULGARIA.CL8MSWIN1251 |
| Catalan | CATALAN_CATALONIA.WE8MSWIN1252 |
| Chinese (PRC) | SIMPLIFIED CHINESE_CHINA.ZHS16GBK |
| Chinese (Taiwan) | TRADITIONAL CHINESE_TAIWAN.ZHT16MSWIN950 |
| Croatian | CROATIAN_CROATIA.EE8MSWIN1250 |
| Czech | CZECH_CZECH REPUBLIC.EE8MSWIN1250 |
| Danish | DANISH_DENMARK.WE8MSWIN1252 |
| Dutch (Netherlands) | DUTCH_THE NETHERLANDS.WE8MSWIN1252 |
| English (United Kingdom) | ENGLISH_UNITED KINGDOM.WE8MSWIN1252 |
| English (United States) | AMERICAN_AMERICA.WE8MSWIN1252 |
| Estonian | ESTONIAN_ESTONIA.BLT8MSWIN1257 |
| Finnish | FINNISH_FINLAND.WE8MSWIN1252 |
| French (Canada) | CANADIAN FRENCH_CANADA.WE8MSWIN1252 |
| French (France) | FRENCH_FRANCE.WE8MSWIN1252 |
| German (Germany) | GERMAN_GERMANY.WE8MSWIN1252 |
| Greek | GREEK_GREECE.EL8MSWIN1253 |
| Hebrew | HEBREW_ISRAEL.IW8MSWIN1255 |
| Hungarian | HUNGARIAN_HUNGARY.EE8MSWIN1250 |
| Icelandic | ICELANDIC_ICELAND.WE8MSWIN1252 |
| Indonesian | INDONESIAN_INDONESIA.WE8MSWIN1252 |
| Italian (Italy) | ITALIAN_ITALY.WE8MSWIN1252 |
| Japanese | JAPANESE_JAPAN.JA16SJIS |
| Korean | KOREAN_KOREA.KO16MSWIN949 |
| Latvian | LATVIAN_LATVIA``.BLT8MSWIN1257 |
| Lithuanian | LITHUANIAN_LITHUANIA.BLT8MSWIN1257 |
| Norwegian | NORWEGIAN_NORWAY.WE8MSWIN1252 |
| Polish | POLISH_POLAND.EE8MSWIN1250 |
| Portuguese (Brazil) | BRAZILIAN PORTUGUESE_BRAZIL.WE8MSWIN1252 |
| Portuguese (Portugal) | PORTUGUESE_PORTUGAL.WE8MSWIN1252 |
| Romanian | ROMANIAN_ROMANIA.EE8MSWIN1250 |
| Russian | RUSSIAN_CIS.CL8MSWIN1251 |
| Slovak | SLOVAK_SLOVAKIA.EE8MSWIN1250 |
| Spanish (Spain) | SPANISH_SPAIN.WE8MSWIN1252 |
| Swedish | SWEDISH_SWEDEN.WE8MSWIN1252 |
| Thai | THAI_THAILAND.TH8TISASCII |
| Spanish (Mexico) | MEXICAN SPANISH_MEXICO.WE8MSWIN1252 |
| Spanish (Venezuela) | LATIN AMERICAN SPANISH_VENEZUELA.WE8MSWIN1252 |
| Turkish | TURKISH_TURKEY.TR8MSWIN1254 |
| Ukrainian | UKRAINIAN_UKRAINE.CL8MSWIN1251 |
| Vietnamese | VIETNAMESE_VIETNAM.VN8MSWIN1258 |
原文作者: Hi.MogDB
原文链接: https://hi.mogdb.org/posts/f4a90812/
许可协议: 知识共享署名-非商业性使用 4.0 国际许可协议