CentOS Kettle不同字符集数据库之间中文乱码问题

手头有个古老的数据库来的数据源,用的是US7ASCII编码,现有的库是ZHS16GBK编码,需要在CentOS搭建的ETL服务器上完成数据导入,来自https://www.hsli.top

尝试了各种方法,主要记录如下:

SSH中乱码

对于Windows,需要设置环境变量NLS_LANG与数据库服务器中通过下列语句查询结果一样的编码方式

1
2
3
4
5
SQL> select userenv('language') from dual;

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

对于Linux,需要在环境变量中加入NLS_LANG参数

1
vim /etc/profile

加入

1
export NLS_LANG='AMERICAN_AMERICA.ZHS16GBK'

并且,所用的SSH终端记得选择相应的编码方式

mark

Kettle预览乱码

Windows中通过勾选允许建议转换就可以了

mark

Linux中就麻烦了,摸索了好久才发现

打开spoon.sh,找到JVM的启动参数段

1
2
3
OPT="$OPT $PENTAHO_DI_JAVA_OPTIONS
-Dfile.encoding=GBK
-Dhttps.protocols=TLSv1,TLSv1.1,TLSv1.2 -Djava.library.path=$LIBPATH -DKETTLE_HOME=$KETTLE_HOME -DKETTLE_REPOSITORY=$KETTLE_REPOSITORY -DKETTLE_USER=$KETTLE_USER -DKETTLE_PASSWORD=$KETTLE_PASSWORD -DKETTLE_PLUGIN_PACKAGES=$KETTLE_PLUGIN_PACKAGES -DKETTLE_LOG_SIZE_LIMIT=$KETTLE_LOG_SIZE_LIMIT -DKETTLE_JNDI_ROOT=$KETTLE_JNDI_ROOT"

加入-Dfile.encoding=GBK参数

Kettle多表转换中批量选择允许建议转换

由于Kettle有多表复制功能,自动生成各个表的转换流程,但是默认不勾选允许建议转换,此时可以用Notepad++打开所有由Kettle生成的ktr文件,查找替换<lazy_conversion_active>Y</lazy_conversion_active>,当然是将N换成Y了

不同字符的存储长度问题

中文字符集会占用更多的存储空间,一些本来足够长的varchar2字段换了字符集就不够长了

怎么办呢,我先用PL/SQL把数据库的结构导出为SQL脚本,然后将所有varchar2字段长度加长,比如说乘上3就好了

至于怎么处理这个SQL脚本,就有意思了

我写了个Python,把所有的varchar2长度都乘了3,再把这个sql脚本用PL/SQL生成数据库表结构,再用Kettle导入,就好了

Python脚本如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#coding:utf-8

# private02数据库编码有些问题,转换编码之后,原来的字段长度又不够放下新的编码内容了,写了个脚本,把数据库生成脚本的所有相关字段长度都乘上3

import re

file = open("G:\\Inspur\\PowerDesigner\\BusinessData\\private02.sql",)

pattern1 = re.compile(r'(^\s+.*?VARCHAR2\()(\d+)(\).*)')
pattern2 = re.compile(r'(^\s+\S+\s+CHAR\()(\d+)(\).*)')

while 1:
line = file.readline()
if not line:
break

if re.match(pattern1,line):
items = re.findall(pattern1,line)
updated_num = int(items[0][1])*3
updated_num = 4000 if updated_num>4000 else updated_num
print items[0][0],str(updated_num),items[0][2]

elif re.match(pattern2,line):
items = re.findall(pattern2,line)
updated_num = int(items[0][1]) * 3
print items[0][0],str(updated_num),items[0][2]

else:
print line


file.close()
如果文章有用,请随意打赏