记录一次把公司开发环境oracle数据库字符集强制修改后报废又还原的过程。
背景:
- 现场用数据泵导了一份19c数据库的dmp文件,字符集是ZHS16GBK,想要导入到公司开发环境;
- 公司2个oracle数据库,一台10g版本,字符集与现场一样是ZHS16GBK,另一台是12c版本的,字符集是AL32UTF8;
- 导进10g数据库时,由于版本不兼容的问题,无法导入,impdp时指定VERSION=19.0也无效;
- 导进12c数据库时,由于字符集编码不同,导致中文字符占位过多,超出了表字段长度,无法将所有数据导入;
于是鬼使神差的想着去改12c数据库的字符集,从AL32UTF8改成ZHS16GBK,在网上找了常规的更改oracle数据库字符集的方法,
改的过程中也提示了“新字符集必须为旧字符集的超集”,想都没想就执行了以下语句:
ALTER DATABASE character set INTERNAL_USE ZHS16GBK;
结果导致整个数据库已经存在的含中文数据的表都中文乱码了,其他部门领导都找上门了。瞬间炸了!
连忙使用原来的方式改回AL32UTF8字符集,结果sysdba上的字符集已经改回成了AL32UTF8,但是其他实例用户都还是停留在ZHS16GBK字符集,死活改不回去。更崩溃了,已经开始估量损失了……
找公司元老级工程师,人家根本不想帮你,说:“字符集不能乱改的呀,改了么就坏了呀!”。彻底崩溃!
最后查资料发现oracle 12c 属于可插拔数据库,每个pdb应该可以单独设置字符集,于是找了oracle12c单独修改pdb字符集的方法,结果在最后一步,执行设置字符集语句的时候报错了,大概意思是“执行此操作时存在其他会话”,于是想到这个数据库上连了很多应用,很多JDBC连接没有关闭,即使杀掉这些session也会立马重连,于是想到了常规修改字符集方法中的“启动挂载模式”,于是死马当活马医,两种修改形式结合一起来用,当时也不知道中文连续经过不同的字符集编码后还能不能变回去。
于是有了以下执行步骤:
1.首先以sysdba的身份登录上去 conn /as sysdba
sqlplus / as sysdba
2.关闭数据库
SQL> shutdown immediate
3.以mount(挂载方式)打开数据库
SQL> startup mount
4.设置session
SQL> ALTER SYSTEM ENABLE RESTRICTED SESSION;
SQL> ALTER SYSTEM SET JOB_QUEUE_PROCESSES=0;
SQL> ALTER SYSTEM SET AQ_TM_PROCESSES=0;
5.启动数据库
SQL> alter database open;
6.查看pdb
SQL> show pdbs;
7.将当前会话指定为当前要修改字符集的pdb
SQL> alter session set container=PDB1;
8.查看当前pdb的字符集
SQL> select userenv('language') from dual;
9.关闭即时实例
SQL> alter pluggable database PDB1 close immediate instances=all;
10.开发读写权限
SQL> alter pluggable database PDB1 open read write restricted;
11.重新指定pdb
SQL> alter session set container=PDB1;
12.修改字符集
SQL> alter database character set internal_use AL32UTF8;
13.关闭可插拔数据库
SQL> alter pluggable database PDB1 close immediate;
14.打开可插拔数据库
SQL> alter pluggable database PDB1 open;
15.检查当前pdb的字符集
SQL> select userenv('language') from dual;
16.关闭以挂载模式启动的数据库
SQL> shutdown immediate
17.正常启动数据库
SQL> Startup
大功告成!
当看到所有数据库用户的表内数据都恢复成中文了,跟做梦一样!再也不乱动数据库字符集了。
最后让现场重新导出dmp文件,指定成10g数据库的版本后的dmp能顺利导入到10g数据库中。