以前也看了一些关于字符集转换的文章,但是实际使用的时候还是发生了问题,出现了乱码,为了彻底搞清楚字符集问题,我决定做测试,用EXP/IMP工具在不同字符集之间互相转换数据。
环境:两台测试PC机器,分称A机器(192.168.1.5)和B机器(192.168.1.8)
两台机器的配置都是一致的,安装WIN2000操作系统和Oracle8.1.7数据库
计划从A机器导出包含有中文的数据,然后倒入到B机器中。
测试计划:
分别在两台机器上安装两个instance,这两个instance又分别是中,英文字符集。
为了简单起见,国家字符集和字符集设置都是一样的,就是说,设置成英文字符集的时候,上面说的两个设置都是US7ASCII,设置中文字符集的时候都是ZHS16GBK,我没有考虑国家字符集和字符集不一致的情况。
客户端也分成C,D两个部分,实际测试的时候C和D是一个客户端,因为假如A和C的字符集不一致,是不答应导出的;同样,假如B和D的字符集不一致,是不答应导入的。
在C机器上建立四个服务指向上面新建的4个instance。
5c:中文 在A机器上
5e:英文 在A机器上
8c:中文 在B机器上
8e:英文 在B机器上
四个进程都建立相同的用户和表。
Connect system/manager
Create user test identified by test default tablespace users temporary tablespace temp;
Grant connect,resource to test;
Connect test/test
Create table emp(id number(2) , address varchar2(100));
然后只在A机器上的两个进程中插入数据。
Insert into emp(id,address) values(1,'北京市');
Insert into emp(id,address) values(2,'成都市');
Insert into emp(id,address) values(3,'上海市');
Insert into emp(id,address) values(4,'天津市');
Insert into emp(id,address) values(5,'重庆市');
Insert into emp(id,address) values(6,'武汉市');
Insert into emp(id,address) values(7,'广州市');
Commit;
然后测试,过程如下
一:在C机器上测试,C机器是英文字符集
exp system/manager@5c file=c:5c1.dmp owner=test
exp system/manager@5e file=c:5e1.dmp owner=test
都导出成功。
发现上面两个文件的ACSII字符集都是0001
二:在C机器上测试,C机器换成中文字符集
exp system/manager@5c file=c:5c2.dmp owner=test
exp system/manager@5e file=c:5e2.dmp owner=test
发现上面两个文件的ACSII字符集都是0354
A机器上的数据库变换字符集,就是把原来英文字符集数据库换成中文字符集,把原来中文字符集数据库换成英文字符集。
备注:之后没有把原来的数据删掉重新录入中文数据,而是用以前的旧的数据。后来发现:原来英文字符集数据库换成中文字符集后,数据可以正常显示;反之,中文字符集数据库换成英文字符集后,数据已经是乱码了,已经不能正常显示了。
原因:中文字符集占两个字节,英文字符集占一个字节,所以当中文转换成英文的时候,数据库压缩,数据就无法正常显示了。反过来可以正常显示,所以推荐建立数据库的时候用英文字符集,好处多多(包括全文索引的时候)。
所以后来倒出的5c3.dmp和5c4.dmp实际上包含的数据都已经是不对的,测试已经没有意义了。于是我重新进行试验,在变换数据库字符集后,删掉原来的数据库emp表中的数据,插入正确的数据,保证源数据库中的数据是可用的。
重新测试。
然后把A机器上的数据库变换字符集,就是原来是中文的数据库我换成英文,原来是英文的数据库我换成中文,采用的方法是修改props$表。
三:A机器上的数据库变换字符集后。
C机器上导出操作,C机器是英文字符集
exp system/manager@5c file=c:5c3.dmp owner=test
exp system/manager@5e file=c:5e3.dmp owner=test
都导出成功。
发现上面两个文件的ACSII字符集都是0001
四:A机器上的数据库变换字符集后。
C机器上导出操作,C机器是中文字符集
exp system/manager@5c file=c:5c4.dmp owner=test
exp system/manager@5e file=c:5e4.dmp owner=test
都导出成功。
发现上面两个文件的ACSII字符集都是0354
备份上面导出的8个数据文件。
这时候修改上面导出的8个文件的ACSII字符集,进行中英文互换,把0001和0354互换
修改后的文件名都加了一个"_2"标记
小结:
1. 导出的时候,假如客户端和数据库的字符集设置不一致,导出的时候Oracle并没有提示。
2. 导出文件的ACSII字符集和客户端的字符集设置有关,与被导数据库字符集的设置无关。
****************************************
**** 导入操作 ****
****************************************
一:向B的8c倒入操作,客户机D是英文字符集
1. D机器是英文字符集,B机器是中文数据库
imp system/manager@8c file=c:5c1.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5c1.dmp是英文客户端导出的中文数据库文件;ASCII字符集是英文的
导入成功,没有报错信息。
但是不管用中文客户端还是用英文客户端SQL/PLUS访问8C,数据库是乱码(注重:乱码不是问号),实际上导入失败。
2. D机器是英文字符集,B机器是中文数据库
imp system/manager@8c file=c:5c1_2.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5c1_2.dmp是英文客户端导出的中文数据库文件,ASCII字符集是改成中文的;
导入成功,没有报错信息。
但是不管用中文客户端还是用英文客户端SQL/PLUS访问8C,数据库是乱码(注重:乱码不是问号),实际上导入失败。
3. D机器是英文字符集,B机器是中文数据库
imp system/manager@8c file=c:5c2.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5c2.dmp是中文客户端导出的中文数据库文件,ASCII字符集是中文的;
导入成功,没有报错信息。
但是不管用中文客户端还是用英文客户端SQL/PLUS访问8C,数据库是乱码(注重:乱码不是问号),实际上导入失败。
4. D机器是英文字符集,B机器是中文数据库
imp system/manager@8c file=c:5c2_2.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5c2_2.dmp是中文客户端导出的中文数据库文件,但是ASCII字符集是改成英文的;
导入成功,没有报错信息。
但是不管用中文客户端还是用英文客户端SQL/PLUS访问8C,数据库是乱码(注重:乱码不是问号),实际上导入失败。
5. D机器是英文字符集,B机器是中文数据库
imp system/manager@8c file=c:5c3.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5c3.dmp是英文客户端导出的英文数据库文件,但是数据库是换过的,ASCII字符集是英文的;
导入成功,没有报错信息。
但是不管用中文客户端还是用英文客户端SQL/PLUS访问8C,数据库是乱码(注重:乱码不是问号),实际上导入失败。
6. D机器是英文字符集,B机器是中文数据库
imp system/manager@8c file=c:5c3_2.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5c3_2.dmp是英文客户端导出的英文数据库文件,但是数据库是换过的,但是ASCII字符集是改成中文的;
导入成功,没有报错信息。
但是不管用中文客户端还是用英文客户端SQL/PLUS访问8C,数据库是???(注重:问号不是乱码),实际上导入失败。
7. D机器是英文字符集,B机器是中文数据库
imp system/manager@8c file=c:5c4.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5c4.dmp是中文客户端导出的英文数据库文件;但是数据库是换过的。
导入成功,没有报错信息。
但是不管用中文客户端还是用英文客户端SQL/PLUS访问8C,数据库是乱码(注重:乱码不是问号),实际上导入失败。
8. D机器是英文字符集,B机器是中文数据库
imp system/manager@8c file=c:5c4_2.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5c4_2.dmp是中文客户端导出的中文数据库文件,但是数据库是换过的。
导入成功,没有报错信息。
但是不管用中文客户端还是用英文客户端SQL/PLUS访问8C,数据库是乱码(注重:乱码不是问号),实际上导入失败。
9. D机器是英文字符集,B机器是中文数据库
imp system/manager@8c file=c:5e1.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5e1.dmp是英文客户端导出的英文数据库文件
,ASCII字符集是英文的;
导入成功,没有报错信息。
但是不管用中文客户端还是用英文客户端SQL/PLUS访问8C,数据库是乱码(注重:乱码不是问号),实际上导入失败。
10. D机器是英文字符集,B机器是中文数据库
imp system/manager@8c file=c:5e1_2.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5e1_2.dmp是英文客户端导出的英文数据库文件,但是ASCII字符集是换成中文的;
导入成功,没有报错信息。
但是不管用中文客户端还是用英文客户端SQL/PLUS访问8C,数据库是???(注重:问号不是乱码),实际上导入失败。
11. D机器是英文字符集,B机器是中文数据库
imp system/manager@8c file=c:5e2.dmp fromuser=test touser=test ignore=y
8C数据库字符集侵形模?e2.dmp是中文客户端导出的英文数据库文件,ASCII字符集是中文的;
导入成功,没有报错信息。
但是不管用中文客户端还是用英文客户端SQL/PLUS访问8C,数据库是乱码(注重:乱码不是问号),实际上导入失败。
12. D机器是英文字符集,B机器是中文数据库
imp system/manager@8c file=c:5e2_2.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5e2_2.dmp是中文客户端导出的英文数据库文件,但是ASCII字符集是换成英文的;
导入成功,没有报错信息。
但是不管用中文客户端还是用英文客户端SQL/PLUS访问8C,数据库是乱码(注重:乱码不是问号),实际上导入失败。
13. D机器是英文字符集,B机器是中文数据库
imp system/manager@8c file=c:5e3.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5e3.dmp是英文客户端导出的中文数据库文件,但是数据库是换过的,ASCII字符集是英文的;
导入成功,没有报错信息。
但是不管用中文客户端还是用英文客户端SQL/PLUS访问8C,数据库是???(注重:问号不是乱码),实际上导入失败。
14. D机器是英文字符集,B机器是中文数据库
imp system/manager@8c file=c:5e3_2.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5e3_2.dmp是英文客户端导出的中文数据库文件,但是数据库是换过的,但是ASCII字符集是换成中文的;
导入成功,没有报错信息。
但是不管用中文客户端还是用英文客户端SQL/PLUS访问8C,数据库是???(注重:问号不是乱码),实际上导入失败。
15. D机器是英文字符集,B机器是中文数据库
imp system/manager@8c file=c:5e4.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5e4.dmp是中文客户端导出的中文数据库文件,但是数据库是换过的
导入成功,没有报错信息。
但是不管用中文客户端还是用英文客户端SQL/PLUS访问8C,数据库是???(注重:问号不是乱码),实际上导入失败。
16. D机器是英文字符集,B机器是中文数据库
imp system/manager@8c file=c:5e4_2.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5e4_2.dmp是中文客户端导出的中文数据库文件,但是数据库是换过的,但是ASCII字符集是换成英文的;
导入成功,没有报错信息。
但是不管用中文客户端还是用英文客户端SQL/PLUS访问8C,数据库是乱码(注重:乱码不是问号),实际上导入失败。
小结:
1. 导入的时候,假如客户端和数据库的字符集设置不一致,导入的时候Oracle并没有提示。
2. 导入的时候,假如客户端和数据库的字符集设置不一致,ORACLE不进行字符集验证,最终结果是数据库不可用。
3. 至于是乱码还是问号,我没有总结,因为没有必要,反正是数据库不可用。
4. 上面的操作其实没有必要做,因为导入的客户端和目的数据库字符集不一致,导入后肯定不能用,但是为了试验的完整性,我还是自己做了一遍,希望大家不要嫌烦
二:向B的8c倒入操作,客户机是中文字符集
17. D机器是中文字符集,B机器是中文数据库
imp system/manager@8c file=c:5c1.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5c1.dmp是英文客户端导出的中文数据库文件;ASCII字符集是英文的
提示:不支持要求的字符集转换,倒入失败。
18. D机器是中文字符集,B机器是中文数据库
imp system/manager@8c file=c:5c1_2.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5c1_2.dmp是英文客户端导出的中文数据库文件,ASCII字符集是改成中文的;
导入成功,有报错信息。
但是不管用中文客户端还是用英文客户端SQL/PLUS访问8C,数据库是乱码(注重:乱码不是问号),实际上导入失败。
19. D机器是中文字符集,B机器是中文数据库
imp system/manager@8c file=c:5c2.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5c2.dmp是中文客户端导出的中文数据库文件,ASCII字符集是中文的;
导入成功,有报错信息。
但是不管用中文客户端还是用英文客户端SQL/PLUS访问8C,数据库是???(注重:问号不是乱码),实际上导入失败。
20. D机器是中文字符集,B机器是中文数据库
imp system/manager@8c file=c:5c2_2.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5c2_2.dmp是中文客户端导出的中文数据库文件,但是ASCII字符集是改成英文的;
提示:不支持要求的字符集转换,倒入失败。
21. D机器是中文字符集,B机器是中文数据库
imp system/manager@8c file=c:5c3.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5c3.dmp是英文客户端导出的英文数据库文件,但是数据库是换过的,ASCII字符集是英文的;
提示:不支持要求的字符集转换,倒入失败。
22. D机器是中文字符集,B机器是中文数据库
imp system/manager@8c file=c:5c3_2.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5c3_2.dmp是英文客户端导出的英文数据库文件,但是数据库是换过的,但是ASCII字符集是改成中文的;
导入成功,有报错信息。
用英文字符集客户端是???,问号;用中文客户端是正确结果,可以看到中文。
实际上导入成功。
23. D机器是中文字符集,B机器是中文数据库
imp system/manager@8c file=c:5c4.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5c4.dmp是中文客户端导出的英文数据库文件;但是数据库是换过的。ASCII字符集是中文的;
导入成功,有报错信息。
但是不管用中文客户端还是用英文客户端SQL/PLUS访问8C,数据库是乱码(注重:乱码不是问号),实际上导入失败。
24. D机器是中文字符集,B机器是中文数据库
imp system/manager@8c file=c:5c4_2.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5c4_2.dmp是中文客户端导出的中文数据库文件,但是数据库是换过的。ASCII字符集是换成英文的;
提示:不支持要求的字符集转换,倒入失败。
25. D机器是中文字符集,B机器是中文数据库
imp system/manager@8c file=c:5e1.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5e1.dmp是英文客户端导出的英文数据库文件,ASCII字符集是英文的;
提示:不支持要求的字符集转换,倒入失败。
26. D机器是中文字符集,B机器是中文数据库
imp system/manager@8c file=c:5e1_2.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5e1_2.dmp是英文客户端导出的英文数据库文件,但是ASCII字符集是换成中文的;
导入成功,有报错信息。
用英文字符集客户端是???,问号;用中文客户端是正确结果,可以看到中文。
实际上导入成功。
27. D机器是中文字符集,B机器是中文数据库
imp system/manager@8c file=c:5e2.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5e2.dmp是中文客户端导出的英文数据库文件,ASCII字符集是中文的;
导入成功,有报错信息。
但是不管用中文客户端还是用英文客户端SQL/PLUS访问8C,数据库是乱码(注重:乱码不是问号),实际上导入失败。
28. D机器是中文字符集,B机器是中文数据库
imp system/manager@8c file=c:5e2_2.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5e2_2.dmp是中文客户端导出的英文数据库文件,但是ASCII字符集是换成英文的;
提示:不支持要求的字符集转换,倒入失败。
29. D机器是中文字符集,B机器是中文数据库
imp system/manager@8c file=c:5e3.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5e3.dmp是英文客户端导出的中文数据库文件,但是数据库是换过的,ASCII字符集是英文的;
提示:不支持要求的字符集转换,倒入失败。
30. D机器是中文字符集,B机器是中文数据库
imp system/manager@8c file=c:5e3_2.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5e3_2.dmp是英文客户端导出的中文数据库文件,但是数据库是换过的,但是ASCII字符集是换成中文的;
导入成功,有报错信息。
但是不管用中文客户端还是用英文客户端SQL/PLUS访问8C,数据库是???(注重:问号不是乱码),实际上导入失败。
31. D机器是中文字符集,B机器是中文数据库
imp system/manager@8c file=c:5e4.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5e4.dmp是中文客户端导出的中文数据库文件,但是数据库是换过的
导入成功,有报错信息。
用英文字符集客户端是???,问号;用中文客户端是正确结果,可以看到中文。
实际上导入成功。
32. D机器是中文字符集,B机器是中文数据库
imp system/manager@8c file=c:5e4_2.dmp fromuser=test touser=test ignore=y
8C数据库字符集是中文,5e4_2.dmp是中文客户端导出的中文数据库文件,但是数据库是换过的,但是ASCII字符集是换成英文的;
提示:不支持要求的字符集转换,倒入失败。
小结:
1:导入的时候,只有当客户机和服务器的字符集一致的时候才进行倒入的字符集验证,当导入文件(DMP文件)的ASCII字符集和他们一致的时候才能导入,否则报:不支持要求的字符集转换。
2:必要条件是导出文件是可用的,就是说,导出的时候的客户端和服务器端的字符集是一致的。可以解释26和31的成功。
3:26的成功说明了就算是英文的数据库保存中文数据,在导出后修改DMP文件的字符集,还是可以导入到中文数据库中的。
4:31的成功说明了就算数据库是转换过的,但是还是可以正确导出中文数据的。
5:22的成功说明了就算是英文的数据库保存中文数据,在导出后修改DMP文件的字符集,还是可以导入到中文数据库中的。(即使这个英文数据库原来是中文的)
7:最不可理解的是19,为什么不行,按道理说,它应该是最有把握的。
三:向B的8e倒入操作(数据库是英文数据库),客户机D是英文字符集
备注:客户机是中文字符集的情况其实不用测试了,因为客户机和服务器不一致,肯定出现问题。
33. D机器是英文字符集,B机器是英文数据库
imp system/manager@8e file=c:5c1.dmp fromuser=test touser=test ignore=y
5c1.dmp是英文客户端导出的中文数据库文件;ASCII字符集是英文的
导入成功,没有报错信息。
但是不管用中文客户端还是用英文客户端SQL/PLUS访问8E,数据库是乱码(注重:乱码不是问号),实际上导入失败。
34. D机器是英文字符集,B机器是英文数据库
imp system/manager@8e file=c:5c1_2.dmp fromuser=test touser=test ignore=y
5c1_2.dmp是英文客户端导出的中文数据库文件,ASCII字符集是改成中文的;
导入成功,没有报错信息。
但是不管用中文客户端还是用英文客户端SQL/PLUS访问8E,数据库是乱码(注重:乱码不是问号),实际上导入失败。
35. D机器是英文字符集,B机器是英文数据库
imp system/manager@8e file=c:5c2.dmp fromuser=test touser=test ignore=y
5c2.dmp是中文客户端导出的中文数据库文件,ASCII字符集是中文的;
导入成功,没有报错信息。
但是不管用中文客户端还是用英文客户端SQL/PLUS访问8E,数据库是乱码(注重:乱码不是问号),实际上导入失败。
36. D机器是英文字符集,B机器是英文数据库
imp system/manager@8e file=c:5c2_2.dmp fromuser=test touser=test ignore=y
5c2_2.dmp是中文客户端导出的中文数据库文件,但是ASCII字符集是改成英文的;
导入成功,没有报错信息。
但是不管用中文客户端还是用英文客户端SQL/PLUS访问8E,数据库是乱码(注重:乱码不是问号),实际上导入失败。
37. D机器是英文字符集,B机器是英文数据库
imp system/manager@8e file=c:5c3.dmp fromuser=test touser=test ignore=y
5c3.dmp是英文客户端导出的英文数据库文件,但是数据库是换过的,ASCII字符集是英文的;
导入成功,没有报错信息。
用英文客户端SQL/PLUS访问8E,数据库是中文,实际上导入成功。
38. D机器是英文字符集,B机器是英文数据库
imp system/manager@8e file=c:5c3_2.dmp fromuser=test touser=test ignore=y
5c3_2.dmp是英文客户端导出的英文数据库文件,但是数据库是换过的,但是ASCII字符集是改成中文的;
导入成功,没有报错信息。
用英文客户端SQL/PLUS访问8E,数据库是???,倒入不成功。