一 字符集与导出导入问题总结
首先是必须保证Oracle的数据库服务端与客户端字符集一致,这样就能保证数据编码的一致性。
当数据库服务端选用ZHS16GBK时,当导出导入新的数据过程中,数据库服务端会对导入的二进制数据库作ZHS16GBK编码检查,当数据长度为奇数值时,出现数据的最后一个字节对应十进制为:129到254时,会丢失此字节,具体解释见第二节内容。
当数据库服务端选用WE8ISO8859P1时,当导出导入新的数据过程中,数据库服务端会对导入的二进制数据库作WE8ISO8859P1编码检查,逐个字节内容进行,不会有数据丢情况发生,具体解释见第二节内容;
针对在不同的字符集下将密文表数据进行导出导入后会有数据丢失的情况,下面作详细描述。
二 ZHS160GBK与WE8ISO8859P1字符集说明
对于上面提到的两种字符集,ZHS16GBK是Windows系统安装Oracle时,默认的数据库字符集,WE8ISO8859P1是Linux系统的默认安装的数据库字符集。且两种字符集都支持中文,至于国家字符集的选择,这里我们都是选择AF16UTF16。数据库安装完成后,可以用 select userenv('language') from dual 语句进行查看。对于ZHS16GBK字符集,数据库按双字节进行处理,且当字节对应的十进制数从129到254时,Oracle会按双字节处理,从而查找下一个字节内容,两个字节组成一个整体进行处理;但对WE8ISO8859P1,数据库完全是按单字节进行处理,所以不会有什么字节检查。
三当数据库为ZHS16GBK的情况描述
1 数据库端配置
在Windows下我们使用默认的Oracle安装,当要DBCoffer正常工作时,需对listener.ora进行修改,其参考配置如下:
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(SID_NAME = ljb)
(ORACLE_HOME = E:oracleproduct10.2.0db_1)
)
(SID_DESC =
(SID_NAME = PLSExtProc)
(ORACLE_HOME = E:oracleproduct10.2.0db_1)
(ENVS = EXTPROC_DLLS=ANY)
(PROGRAM = extproc)
)
)
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = IPC)(KEY = extproc))
(ADDRESS = (PROTOCOL = TCP)(HOST = Jiabo)(PORT = 1521))
)
)
表1
关于此种情况下的Oracle客户端环境变量的设置,可以在注册表查找到:
NLS_LANG=SIMPLIFIED CHINESE_CHINA.ZHS16GBK
2 加密解密情况描述
正常安装DBCoffer完成后,便可以正常加密解密数据
3 导出导入情况描述
当加密一个表后,我们知道加密后的密文长度都是一个奇数值,当将密文表用exp命令导出数据库后,然后将原密文表重命名,而后将导出的数据导入数据库,此时会出现的情况是密文字段部分数据的最后一个字节内容丢失,当再次将此时导入的密文表再次导出去,并且与原导出的表的二进制文件进行比较时,明显数据对不上,且丢失的字节大小范围都在对应的十进制的129到254,那么这样一来,就可以确定是数据库字符集处理产生的问题,因为密文长度是一个奇数值,假如当密文的数据的最后一个字节内容为129到254时,会出现如前面所描述的情况发生,Oracle服务端会将最后一个字节作双字节处理,如果找不到下一
个字节,则将此字节丢失。
关于以上情况:我们可以用lengthb(密文字段)去查看,原密文表的密文长度都是一个固定的奇数值,而再次导入表密文表的密文字段有部分是比该奇数值小1的,所以针对密文表的查询会报-10004,加密数据不完整。
四当数据库为WE8ISO8859P1的情况描述
1 新建一个Oracle数据库实例iso8859
此步可以利用DBCA工具进行,当进行至第十步时,按下图所示设置数据库字符集。
图 1
2 修改Oracle的listener.ora和tnames.ora的配置
关于listener.ora的配置参考如下:
# listener.ora Network Configuration File: E:oracleproduct10.2.0db_1networkadminlistener.ora
# Generated by Oracle configuration tools.
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(SID_NAME = ljb)
(ORACLE_HOME = E:oracleproduct10.2.0db_1)
)
(SID_DESC =
(SID_NAME = iso8859)
(ORACLE_HOME = E:oracleproduct10.2.0db_1)
)
(SID_DESC =
(SID_NAME = orcl)
(ORACLE_HOME = E:oracleproduct10.2.0db_1)
)
(SID_DESC =
(SID_NAME = PLSExtProc)
(ORACLE_HOME = E:oracleproduct10.2.0db_1)
(ENVS = "EXTPROC_DLLS=ANY,ODC_SECURE_SERVICE_API_CONFIG_FILE=C:DBCofferDBCSecureServiceAPIsecureServiceAPI.conf,NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P1")
(PROGRAM = extproc)
)
)
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = IPC)(KEY = extproc))
(ADDRESS = (PROTOCOL = TCP)(HOST = Jiabo)(PORT = 1521))
)
)
表2
其中请一定注意红色部分的内容,如果用Net Manager修改相关配置后,也请以此文件为参考,否则有可能我们的DBCoffer可能不能正常工作,而在tnames.ora的配置就相对较简单,添加如下内容即可:
ISO8859 =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = 127.0.0.1)(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = iso8859)
)
)
表3
最后重启监听即可。
3 测试新实例
利用sqplus工具进行登录,发现能正常进入,则表明新实例建立成功,接下来我们测试下中文支持情况,发现中文是能插入到表中,但查询出来的中文数据全是“?”,还有最后一个问题,就是修改客户端字符集,因为此时的客户端还是ZHS16GBK,此字符集与
WE8ISO8859P1是不兼容的,即之间没有大小包含关系,所以我们需要修改Oracle客户端NLS_LANG的环境变量,此处为了不要破坏原来实例的数据库环境,所以决定新添加一个Windows用户级的环境变量:NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P1即可,此时再次对中文的支持情况进行测试,发现此时插入与查询都正常。
4 用DBCoffer加密处理
按正常的情况加密、授权、查询、解密,可以看到都正常。
5 数据的导出导入测试
对于当数据库字符集为 ZHS16GBK 时导出导入出现数据丢失的测试用例再次在数据库字符集为 WE8ISO8859P1进行测试,此时上面出现的数据丢问题不复存在,后来再次加大数据量,加密部分字段后,再次导出再导入,依然没有出现数据丢失的情况,解密正常。
五 DBCoffer关于两种字符集在Oracle端的通用配置总结
1 需要重启操作系统的配置参考
系统级环境变量里加一个NLS_LANG的环境变量
NLS_LANG=SIMPLIFIED CHINESE_CHINA.ZHS16GBK
监听器配置参考如下:
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(SID_NAME = ljb)
(ORACLE_HOME = E:oracleproduct10.2.0db_1)
)
(SID_DESC =
(SID_NAME = PLSExtProc)
(ORACLE_HOME = E:oracleproduct10.2.0db_1)
(ENVS = EXTPROC_DLLS=ANY)
(PROGRAM = extproc)
)
)
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = IPC)(KEY = extproc))
(ADDRESS = (PROTOCOL = TCP)(HOST = Jiabo)(PORT = 1521))
)
)
表4
注:请严格按照红色字体格试
修改完成后,请重启操作系统。
2 不需要重启操作系统的配置参考
用户级环境变量里加一个NLS_LANG的环境变量
NLS_LANG=SIMPLIFIED CHINESE_CHINA.ZHS16GBK
监听器配置参考如下:
# listener.ora Network Configuration File: E:oracleproduct10.2.0db_1networkadminlistener.ora
# Generated by Oracle configuration tools.
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(SID_NAME = ljb)
(ORACLE_HOME = E:oracleproduct10.2.0db_1)
)
(SID_DESC =
(SID_NAME = iso8859)
(ORACLE_HOME = E:oracleproduct10.2.0db_1)
)
(SID_DESC =
(SID_NAME = orcl)
(ORACLE_HOME = E:oracleproduct10.2.0db_1)
)
(SID_DESC =
(SID_NAME = PLSExtProc)
(ORACLE_HOME = E:oracleproduct10.2.0db_1)
(ENVS = "EXTPROC_DLLS=ANY,ODC_SECURE_SERVICE_API_CONFIG_FILE=C:DBCofferDBCSecureServiceAPIsecureServiceAPI.conf,NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P1")
(PROGRAM = extproc)
)
)
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = IPC)(KEY = extproc))
(ADDRESS = (PROTOCOL = TCP)(HOST = Jiabo)(PORT = 1521))
)
)
表5
请在此处指定字符集为你的Oracle服务端字符集,具体情况时,红色部分修改成对应的配置内容。
3 关于通用配置的原理说明
此处主要是关于NLS_LANG这个环境变量的说明,客户端依据其最先找到的NLS_LANG作为参考字符集,顺序为:用户级环境变量,系统级环境变量,注册表中Oracle中NLS_LANG;监听器也是依据其NLS_LANG作为其参考字符集,顺序为:在监听器内部指定的NLS_LANG,监听器进程所属用户级环境变量的NLS_LANG,注册表中Oracle中的NLS_LANG。
有此上面所说的原理后,相关先项的内容便可灵活设置,总之保证一点:Oracle客户端和监听器所需要的NLS_LANG与Oracle服务端保持一致。